powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Передача данных C# -> DLL С++ ->SQLite и обратно
25 сообщений из 58, страница 2 из 3
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513376
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArbitОсвобожу память здесь по полученному указателю из DLL - это будет правильно???

Способ выделения памяти должен соответствовать способу её освобождения. Нельзя пришивать
руку на место ноги.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513381
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arbitа если я сделаю как писал выше
C#
Код: c#
1.
2.
3.
            IntPtr pArrImg = DLL_LoadImage(KeyBinary, ref ArrSize);
                ...
                Marshal.FreeCoTaskMem(pArrImg); //Освобожу память здесь по полученному указателю из DLL - это будет правильно??? 


Нельзя так делать, потому что разные менеджеры памяти по разному работают, если по-простому объяснять, то память не выделяется каждый раз, а просто выдается кусок ранее выделенной и делается отметка что кусок занят. Эти отметки разные менеджеры памяти делают по-разному.
Поэтому освобождать память надо теми же средствами что и выделять, т.е. если выделил ее malloc() в С++, то и освободить надо вызовом free() в C++.

Проще всего сделать как YuRock предложил, т.е. добавить в DLL функцию
Код: plaintext
1.
2.
3.
extern "C" __declspec(dllexport) void DLL_FreeMemory(byte* data) {
   free(data);
}


И ее вызвать из C#
Код: c#
1.
2.
3.
            IntPtr pArrImg = DLL_LoadImage(KeyBinary, ref ArrSize);
                ...
            DLL_FreeMemory(pArrImg);
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513523
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем большое большое спасибо все понятно!

Последний вопрос:
В DLL мне надо string перевести в массив, на который я передаю указатель.
1. какой массив лучше принять в С# - байтовый или char?
2. как быть с символом конца строки - в DLL его записывать в массив или нет?

в C# массив ведь нужно будет снова преобразовывать в строку.
Как это правильно сделать?

В общем у меня все вопросы сейчас крутятся вокруг темы обмена различными
данными между managed и unmanaged кодом

Спасибо
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513533
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
string в С++ и C# разные вещи, первый в ANSI кодировках, второй с юникоде, поэтому лучше в C# принимать как массив байт, а затем конвертировать в строку.
Код: plaintext
1.
2.
var encoder = Encoding.GetEncoding(1251);
string result = encoder.GetString(Array, ...);


По поводу нуля: он не нужен, если надо только записать для последующего чтения в C#
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513557
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arbit1. какой массив лучше принять в С# - байтовый или char?
2. как быть с символом конца строки - в DLL его записывать в массив или нет?
лучше сразу char(wchar_t, юникод UTF-16) использовать)
нулевой терминатор - записывать.
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513564
YuRock
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arbitа если я сделаю как писал выше
C#
Код: c#
1.
2.
Marshal.Copy(pArrImg, arrImg, 0, arrImg.Length);
Marshal.FreeCoTaskMem(pArrImg);



Я тут ничего не понимаю, увы.
Но что могу сказать: ты из C# заранее не знаешь и знать не можешь, сколько тебе необходимо памяти выделить. Ну можно, конечно, с запасом полтора гига выделят каждый раз, но это не вариант)

ArbitМне не хочется дважды обращаться к DLL - второй раз для очистки памяти.
Обращаешься ты один раз - при загрузке библиотеки. Далее ты просто вызываешь функции, которые уже ничем не отличаются от функций твоей программы.

Впрочем, как хочешь.
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513568
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если выделять память под строку через ::SysAllocString

и принимать как BSTR - никакого дополнительного кода не нужно, маршаллер сам справится
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513614
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
extern "C" __declspec(dllexport) BSTR __stdcall DLL_Strings(BSTR * p,LPCWSTR p2) {
	::SysFreeString(*p);
	*p = ::SysAllocString(L"second вторая");
	return  ::SysAllocString(p2);
}


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
[DllImport(@"Win32Project1.dll",CallingConvention= CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.BStr)]
        public static extern string DLL_Strings([MarshalAs(UnmanagedType.BStr)]ref string p, [MarshalAs(UnmanagedType.LPWStr),In]string p2);

....
       
string a =   "ячс";
string r = DLL_Strings(ref a,"фыва");
       
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513667
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропил, Сегодня мне счастье привалило, рад видеть! :)
Читаю последний Ваш пост и в голове нестыковка по вопросу очистки памяти.
Если я правильно понял, то очистка памяти в Вашем примере происходит не
в том коде, в котором она выделялась
Код: plaintext
1.
2.
3.
4.
5.
extern "C" __declspec(dllexport) BSTR __stdcall DLL_Strings(BSTR * p,LPCWSTR p2) {
	::SysFreeString(*p);
	*p = ::SysAllocString(L"second вторая");
	return  ::SysAllocString(p2);
}


Dimitry Sibiryakov и Дима Т в один голос говорят, что нужно чистить память там где она выделалась

Ранее мы с Вами разбирали этот вопрос
Изопропилкороче - возвращай из C - из сишного кода память выделенную CoTaskMemAlloc
принимай в с# как IntPtr,
Marshal.Copy - скопирует,
Marshal.FreeCoTaskMem - освободит
У меня это все работало и передавались данные (изображения) и нигде память не затиралась
Говорят что мне просто везло
Где-то я что-то напутал наверное.
Проясните пожалуйста
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513669
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
YuRock,
YuRockНо что могу сказать: ты из C# заранее не знаешь и знать не можешь, сколько тебе необходимо памяти выделить. Ну можно, конечно, с запасом полтора гига выделят каждый раз, но это не вариант)
Не, память я выделяю в DLL и возвращаю в С# указатель на массив и его размер в параметре
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513674
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArbitDimitry Sibiryakov и Дима Т в один голос говорят, что нужно чистить память там где она выделалась
это может упростить жизнь.

Но если мы знаем, как память выделялась и как работает маршаллер(или вручную маршаллинг делаем)
можно позволить себе выделять в одном месте, а освобождать в другом.
главное чтоб единые распределители памяти использовались(CoTaskMemAlloc-CoTaskMemFree,
SysAllocString-SysFreeString,GlobalAlloc-GlobalFree) ну а если случилось выделение malloc или new -
только так, где выделяли освобождать следует.


Например, массив, передаваемый по ссылке(ref) из c# кода маршаллером копируется в память, выделенную
CoTaskMemAlloc. C-код в dll имеет полное право сделать CoTaskMemFree и CoTaskMemAlloc.
а если строки передавались в массиве структур - то перед освобождением массива нужно ещё для строк сделать SysFreeString
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513677
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропил,

авторArbit
1. какой массив лучше принять в С# - байтовый или char?
2. как быть с символом конца строки - в DLL его записывать в массив или нет?

Изопропиллучше сразу char(wchar_t, юникод UTF-16) использовать)
нулевой терминатор - записывать.
Я сейчас передаю не короткие строки, а
сериализованную XML строку с данными из базы для передачи их в DataTable
Таблица в XML содержит 200-300 строк
Такую большую XML строку тоже лучше передавать как массив char?
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513680
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArbitТакую большую XML строку тоже лучше передавать как массив char?ну она не такая уж и большая. я бы string передал (и длину передавать не придётся) и в utf-16 сразу бы перекодировал
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513681
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ArbitИзопропил,

авторArbit
1. какой массив лучше принять в С# - байтовый или char?
2. как быть с символом конца строки - в DLL его записывать в массив или нет?

пропущено...
.
Я сейчас передаю не короткие строки, а
сериализованную XML строку с данными из базы для передачи их в DataTable
Таблица в XML содержит 200-300 строк
Такую большую XML строку тоже лучше передавать как массив char?
Прикинь в байтах: 200-300 строк даже если каждая 1 Кб, это всего 0.2-0.3 Мб, ниочем. Передавай как передастся и не заморачивайся.
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513684
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ИзопропилArbitDimitry Sibiryakov и Дима Т в один голос говорят, что нужно чистить память там где она выделалась
это может упростить жизнь.

Но если мы знаем, как память выделялась и как работает маршаллер(или вручную маршаллинг делаем)
можно позволить себе выделять в одном месте, а освобождать в другом.
главное чтоб единые распределители памяти использовались(CoTaskMemAlloc-CoTaskMemFree,
SysAllocString-SysFreeString,GlobalAlloc-GlobalFree
) ну а если случилось выделение malloc или new -
только так, где выделяли освобождать следует.

Например, массив, передаваемый по ссылке(ref) из c# кода маршаллером копируется в память, выделенную
CoTaskMemAlloc. C-код в dll имеет полное право сделать CoTaskMemFree и CoTaskMemAlloc.
а если строки передавались в массиве структур - то перед освобождением массива нужно ещё для строк сделать SysFreeString
Вот она - Квинтэссенция!!!
Огромное спасибо!
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513686
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Dima T, Спасибо!
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513688
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ИзопропилArbitТакую большую XML строку тоже лучше передавать как массив char?ну она не такая уж и большая. я бы string передал (и длину передавать не придётся) и в utf-16 сразу бы перекодировал
Спасибо!
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513690
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Дорогие Гуру!
Всем премного благодарен за помощь и внимание!
Всем хорошего отдыха в грядущие выходные!


Пошел ваять
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513705
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Arbit,

примечание - максимум вспомогательного кода лучше иметь на одной стороне
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513706
Siemargl
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
как же скучно я живу....

а тут столько эмоций на нечетном байте =(
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513762
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропил,
А что подразумевается под вспомогательным кодом?
И на какой стороне его предпочтительнее иметь? С++ или С#?

Вообще у меня основной код в DLL - работа с базой, вся промежуточная обработка данных перед и после базы
В С# только код по работе с пользовательским интерфейсом ввод и отображение данных
Да, еще в С# есть код по работе с моим сервером в интернете, но я его тоже перенесу в DLL (пока до этого руки еще не дошли)

Спасибо за совет
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513803
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вспомогательный код - например вот
Arbit
Код: c#
1.
2.
Marshal.Copy(pArrImg, arrImg, 0, arrImg.Length);
Marshal.FreeCoTaskMem(pArrImg);


имеет отношение к маршаллингу, но не к решаемой прикладной задаче
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39513898
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропил,
Изопропилимеет отношение к маршаллингу, но не к решаемой прикладной задаче
Да, я учту это.
Спасибо большое
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39514161
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Изопропил,
В итоге у получился такой вариант
С++
Код: plaintext
1.
2.
3.
4.
5.
6.
extern "C" __declspec(dllexport) BSTR DLL_Select(const char* pQueryName, const char* pWhereValues, int  *CountRow)
{
string strXML  // это сериализованная base64 XML строка 
_bstr_t XML = _bstr_t(strXML.c_str());	
	return ::SysAllocString(XML);
}


С#
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
[DllImport(@"D:\ProjectsC#\FinStudio\Debug\FinStudioDLL.dll", CallingConvention = CallingConvention.Cdecl)]
        [return: MarshalAs(UnmanagedType.BStr)]
 public static extern string DLL_Select(string QueryName, string WhereValues, ref int CountRows);

public static bool Select(string QueryName, ref DataTable dt, string WhereValues="")
        {
                string strXML = DLL_Select(QueryName, WhereValues, ref CountRows); 
                strXML = Main.Base64DecodeString(strXML);
                using(StringReader rd = new StringReader(strXML))
                {
                    dt.ReadXml(rd);
                    rd.Dispose();
                }
            return true;
        }


Все работает, передаются любые объемы данных

Теперь по очистке выделенной памяти:
Память выделялась в С++ с помощью SysAllocString
В С# маршаллер передал BSTR в string strXML
А как теперь освободить память после заполнения DataTable?
Есть Marshal.FreeCoTaskMem, Marsha.lFreeHGlobal, Marshal.FreeBSTR
Но Marshal. SysFreeString не нашел
Может - в данном случае это Marshal. FreeBSTR ?

Или string strXML очистит сборщик мусора С#?

Спасибо.
...
Рейтинг: 0 / 0
Передача данных C# -> DLL С++ ->SQLite и обратно
    #39514189
Arbit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Или маршаллер в данном случае уже сам позаботился об очистке памяти?
...
Рейтинг: 0 / 0
25 сообщений из 58, страница 2 из 3
Форумы / C++ [игнор отключен] [закрыт для гостей] / Передача данных C# -> DLL С++ ->SQLite и обратно
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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