После компиляции портятся/теряются данные

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

После компиляции портятся/теряются данные

Сообщение pronto » 23.06.2015 (Вт) 7:06

Доброго времени суток, уважаемые форумчане!
Столкнулся с проблемой некорректного копирования? данных. Эффект наблюдается только после компиляции проекта.
Имеется:
— обычный модуль с кучей функций и процедур;
— в модуле объявлен UDT;
Код: Выделить всё
Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (ByVal Dest As Long, ByVal Source As Long, ByVal Length As Long)
Private Type INDEX_STATISTICS
   statKeys As Long
   statMaxLen As Long
   statMemUsage As Long
   statBytesPerKey As Single
   statTblUsage As Long
End Type
Private StatInfo As INDEX_STATISTICS

— на вызывающей стороне (форме) тоже объявлен этот UDT;
— из формы идёт обращение к функции получения статистики;
— эта функция возвращает указатель на заполненый UDT (Module1.Statistics = VarPtr(StatInfo));
— на вызывающей стороне, функцией CopyMemory, данные копируются в такой же UDT (пробовал объявление RtlMoveMomory, но оно и в режиме отладки даёт «пургу»);
— поля UDT, с применением форматирования строки (Format()), распихиваются по лейблам.

Данные проверялись — на стороне функции Statistics корректные. Не могу понять, где зарыт косяк?
Последний раз редактировалось pronto 23.06.2015 (Вт) 7:38, всего редактировалось 1 раз.
O, sancta simplicitas!

Jack Ferre
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 132
Зарегистрирован: 17.02.2014 (Пн) 14:31
Откуда: Казахстан, Костанай

Re: После компиляции портятся/теряются данные

Сообщение Jack Ferre » 23.06.2015 (Вт) 7:23

Можно пример без "кучи функций и процедур"?

pronto писал(а):— эта функция возвращает указатель на заполненый UDT

А что мешает возвращать UDT?

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: После компиляции портятся/теряются данные

Сообщение pronto » 23.06.2015 (Вт) 7:36

Jack Ferre писал(а):Можно пример без "кучи функций и процедур"?

Долго выколупывать...
Jack Ferre писал(а):А что мешает возвращать UDT?

Ничего не мешает. Такой вариант работает, но мне хочется понять/решить проблему с CopyMemory (т.к. иногда нельзя обойтись UDT).
O, sancta simplicitas!

Jack Ferre
Продвинутый пользователь
Продвинутый пользователь
Аватара пользователя
 
Сообщения: 132
Зарегистрирован: 17.02.2014 (Пн) 14:31
Откуда: Казахстан, Костанай

Re: После компиляции портятся/теряются данные

Сообщение Jack Ferre » 23.06.2015 (Вт) 8:00

pronto писал(а):Не могу понять, где зарыт косяк?

А как должны понять остальные, если нет кода?

bon818
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 267
Зарегистрирован: 29.08.2009 (Сб) 4:49
Откуда: Ташкент

Re: После компиляции портятся/теряются данные

Сообщение bon818 » 23.06.2015 (Вт) 9:01

pronto писал(а):— на вызывающей стороне (форме) тоже объявлен этот UDT;
— из формы идёт обращение к функции получения статистики;
— эта функция возвращает указатель на заполненый UDT (Module1.Statistics = VarPtr(StatInfo));
— на вызывающей стороне, функцией CopyMemory, данные копируются в такой же UDT (пробовал объявление RtlMoveMomory, но оно и в режиме отладки даёт «пургу»);


— на вызывающей стороне, что там? CopyMemory VarPtr(StatInfoForm), FunctionStatistics(), Len(StatInfoForm)

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: После компиляции портятся/теряются данные

Сообщение pronto » 23.06.2015 (Вт) 11:54

Да, почти так:
Код: Выделить всё
RetVal = Statistics(id_Type)
CopyMemory VarPtr(IndexInfo), RetVal, LenB(IndexInfo)
O, sancta simplicitas!

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: После компиляции портятся/теряются данные

Сообщение Хакер » 23.06.2015 (Вт) 12:14

pronto писал(а):— эта функция возвращает указатель на заполненый UDT (Module1.Statistics = VarPtr(StatInfo));

Что гадаем?
Исходя из описания ситуая, структура StatInfo объявлена как локальная переменная в рамках вызываемой функции.
После того, как происходит возврат из вызываемой функции, указатель на локальную переменную из её стекового фрейма перестаёт иметь какой-либо разумный смысл.

При всём при этом, иметь две декларации одной и той же UDT и присваивание делать с помощью CopyMemory — крайне дурной тон и криминимальная практика.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: После компиляции портятся/теряются данные

Сообщение pronto » 23.06.2015 (Вт) 12:40

Хакер, ты в очередной раз подтвердил своё звание телепата! Уважаю!
Но. Почему в режиме отладки это работает, и вылазит только после компиляции? Остаётся загадкой.
Хакер писал(а):При всём при этом, иметь две декларации одной и той же UDT и присваивание делать с помощью CopyMemory — крайне дурной тон и криминимальная практика.

Выход? Объявлять UDT в модуле публично? Отказаться от CopyMemory при работе с UDT?
O, sancta simplicitas!

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Re: После компиляции портятся/теряются данные

Сообщение alibek » 23.06.2015 (Вт) 12:42

Используй для хранения данных байтовый массив, например.
Lasciate ogni speranza, voi ch'entrate.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: После компиляции портятся/теряются данные

Сообщение Хакер » 23.06.2015 (Вт) 12:46

pronto писал(а):Почему в режиме отладки это работает, и вылазит только после компиляции?

Немного другая модель управления памятью под временные данные. На стеке, очевидно, размещается только указатель на UDT, сама UDT живёт в куче (heap), после соответствующего вызова HeapFree старые данные структуры не зануляются, поэтому данные структуры на правах мусора остаются в памяти.

pronto писал(а):Выход? Обявлять UDT в модуле публично? Отказаться от CopyMemory при работе с UDT?

Выход из чего?
Чтобы не иметь две UDT, нужно саму переменную в одном месте. Это должно быть единственное авторитетное объявление UDT, исключающее вероятность, что в одном объявлении захотят добавить новое поле, а во втором объявлении это забудут. (Это основная причина, почему это плохо и криминально)
Это может быть как публичное объявление в модуле, так и объявление в TLB (что особенно хорошо, если предполагается взаимодействие со сторонним кодом на уровне передачи ему указателей на нашу UDT или приёма таких указателей от него).

Выход из описываемого бага — заполнять не локальную переменную, а глобальную, и возвращать указатель на неё. Или выделять память в самой процедуре и заполнять выделенный фрагмент данными и возвращать указатель на него, а не вызывающую сторону возложить обязанность по освобожению памяти. Это конечно не очень хорошо, потому что заставляет прибегать к ручному управлению памятью, что может не сработать из-за забывчивости программиста или недальновидности программиста (если есть вероятность, что до вызова free-функции дело не дойдёт из-за ошибки и ухода выполнения на error handler). Если подумать в сторону автоматического управления памятью — то мы приходим к очень простой вещи — к идеи использовать вместо UDT класс.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: После компиляции портятся/теряются данные

Сообщение Хакер » 23.06.2015 (Вт) 12:51

alibek писал(а):Используй для хранения данных байтовый массив, например.

А как это изменит ситуацию?

Если байтовый массив будет объявлен локально, то он так же перестанет существовать, как его локальная переменная.
Если использовать глобальный байтовый массив, то это ничем не лучше использования глобальной объявленной переменной As UDT, но больше геморроя.
Если изменить саму семантику взаимодействия, убрав необходимость копирования на стороне вызывающей стороны, то придётся делать интерфейс для освобождения регионов байтового массива и контролем его фрагментации.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Re: После компиляции портятся/теряются данные

Сообщение alibek » 23.06.2015 (Вт) 12:52

ЕМНИП публичный UDT требует тип проекта ActiveX EXE.
А публичный массив не требует.
Lasciate ogni speranza, voi ch'entrate.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: После компиляции портятся/теряются данные

Сообщение Хакер » 23.06.2015 (Вт) 12:57

Публичный UDT в модуле класса, форме или контролле — требует проекта типа ActiveX EXE или ActiveX DLL или ActiveX Control.
Публичный UDT в обычном модуле не требует особого типа проекта.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: После компиляции портятся/теряются данные

Сообщение pronto » 23.06.2015 (Вт) 13:08

Самый простой вариант
В модуле:
Код: Выделить всё
Private Type INDEX_STATISTICS
   statKeys As Long
   statMaxLen As Long
   statMemUsage As Long
   statBytesPerKey As Single
   statTblUsage As Long
End Type
Public StatInfo As INDEX_STATISTICS

В форме никаких копирований:
Код: Выделить всё
lblStat(0).Caption = StatInfo.statKeys
O, sancta simplicitas!

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: После компиляции портятся/теряются данные

Сообщение ger_kar » 23.06.2015 (Вт) 14:23

Этот код странен тем, что структура объявляется приватной, а переменная с этим типом публичной.
По идее это противоречие.
Бороться и искать, найти и перепрятать

bon818
Бывалый
Бывалый
Аватара пользователя
 
Сообщения: 267
Зарегистрирован: 29.08.2009 (Сб) 4:49
Откуда: Ташкент

Re: После компиляции портятся/теряются данные

Сообщение bon818 » 23.06.2015 (Вт) 14:36

Хакер писал(а):
pronto писал(а):— эта функция возвращает указатель на заполненый UDT (Module1.Statistics = VarPtr(StatInfo));

Что гадаем?
Исходя из описания ситуая, структура StatInfo объявлена как локальная переменная в рамках вызываемой функции.

Хорошая догадка, если учесть что Private StatInfo As INDEX_STATISTICS и находится в поле объявлений.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: После компиляции портятся/теряются данные

Сообщение pronto » 23.06.2015 (Вт) 15:09

В том то и дело, что в проекте переменная была объявлена на уровне процедуры!.. А когда писал в форум, то безсознательно :) привёл одно из решений проблемы... Конечно, было бы приятней самостоятельно додуматься, ведь про уничтожение локальных переменных при выходе из процедуры усваивается сызмальства. Повторение — мать учения.
O, sancta simplicitas!

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: После компиляции портятся/теряются данные

Сообщение ger_kar » 23.06.2015 (Вт) 15:26

Хакер писал(а):pronto писал(а):Почему в режиме отладки это работает, и вылазит только после компиляции? Немного другая модель управления памятью под временные данные. На стеке, очевидно, размещается только указатель на UDT, сама UDT живёт в куче (heap), после соответствующего вызова HeapFree старые данные структуры не зануляются, поэтому данные структуры на правах мусора остаются в памяти.
А зачем понадобилось так изменять модель управления памятью? Так лучше для отладки?
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: После компиляции портятся/теряются данные

Сообщение Хакер » 23.06.2015 (Вт) 20:33

bon818 писал(а):Хорошая догадка, если учесть что Private StatInfo As INDEX_STATISTICS и находится в поле объявлений.

pronto писал(а):В том то и дело, что в проекте переменная была объявлена на уровне процедуры!.. А когда писал в форум, то безсознательно :) привёл одно из решений проблемы...

Телепатия — страшная сила.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 57

    TopList