Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Заполнение структур 
:(
    Опции темы
GydruS
  Дата 1.10.2010, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 1.10.2010

Репутация: нет
Всего: нет



Почму не работает вот такой код:

Код

...
struct TNodeData
{
    AnsiString Name;
    int ImageIndex;
};

void test()
{
    ...

    TNodeData NodeData;
    NodeData.Name = "TestName";
    Node = DirectoryTreeView->AddChild(RootNode, &NodeData);

    TNodeData* SavedNodeData = (TNodeData*)DirectoryTreeView->GetNodeData(Node);
    ShowMessage(SavedNodeData->Name); // показывает пустую строку. Если выполнить из другой процедуры - так вообще ошибку вываливает.
}
...


А вот такой работает:

Код

...
struct TNodeData
{
    AnsiString Name;
    int ImageIndex;
};

void test()
{
    ...

    Node = DirectoryTreeView->AddChild(RootNode, NULL);
    TNodeData* NodeData = (TNodeData*)DirectoryTreeView->GetNodeData(Node);
    NodeData->Name = "TestName!";

    TNodeData* SavedNodeData = (TNodeData*)DirectoryTreeView->GetNodeData(Node);
    ShowMessage(SavedNodeData->Name); // показывает "TestName". Что "здесь", что из другой процедуры.
}
...


Товарищи, пожалуйста, подскажите, что в первом варианте не так?


ps:
Код

function GetNodeData(Node: PVirtualNode): Pointer;
function AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode;

PM MAIL   Вверх
xvr
Дата 1.10.2010, 14:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Оба варианта неправильные.
Правильно будет
Код

...
struct TNodeData
{
    AnsiString Name;
    int ImageIndex;
};
void test()
{
    ...
    Node = DirectoryTreeView->AddChild(RootNode, new TNodeData);
    TNodeData* NodeData = (TNodeData*)DirectoryTreeView->GetNodeData(Node);
    NodeData->Name = "TestName!";
    TNodeData* SavedNodeData = (TNodeData*)DirectoryTreeView->GetNodeData(Node);
    ShowMessage(SavedNodeData->Name); // показывает "TestName". Что "здесь", что из другой процедуры.
}
...
И не забыть удалить все NodeData из DirectoryTreeView при завершении программы.

Проблема в том, что DirectoryTreeView->AddChild просто сохраняет 2й параметр вместе с данными узла, она не копирует содержимое структуры, которое ей передали, и вообще с ней ничего не делает.
И когда вы пытаетесь потом что то прочесть по этому указателю, то все ломается, т.к. он смотрит в стек давно завершенной процедуры, где когда то была переменная TNodeData NodeData

PM MAIL   Вверх
GydruS
Дата 2.10.2010, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 1.10.2010

Репутация: нет
Всего: нет



xvr, спасибо за ответ!
но я виноват - не весь нужный код привел.
Выделять память под TNodeData не надо. DirectoryTreeView это делает сам (как и освобождает память).
И до вызова AddChild есть такая строка:
Код

DirectoryTreeView->NodeDataSize = sizeof(TNodeData);

И как я уже писал, второй вариант прекрасно работает с любым кол-вом данных при вызове их из любого другого метода главной формы.
Меня мучал вопрос - почему не работает первый?
Но я разобрался, когда полез рыться в исходники компонента, который использовал как DirectoryTreeView. Баг был там. С его учетом заработала вот такая конструкция:
Код

void* NodeData = DirectoryTreeView->GetNodeData(Node);
ShowMessage( ((TNodeData)(*(*(TNodeData**)NodeData))).Name );

А ошибка вызова из другой ф-ии была связана с областью видимости переменной + с тем же багом.
Вот он, если интересно (выделил жирным):
Код

function TBaseVirtualTree.GetNodeData(Node: PVirtualNode): Pointer;
begin
  Assert(FNodeDataSize > 0, 'NodeDataSize not initialized.');
  if (FNodeDataSize <= 0) or (Node = nil) or (Node = FRoot) then
    Result := nil
  else
    Result := PByte(@Node.Data) + FTotalInternalDataSize;
end;
...
function TBaseVirtualTree.AddChild(Parent: PVirtualNode; UserData: Pointer = nil): PVirtualNode;
var
  NodeData: ^Pointer;
begin
...
    // Check if there is initial user data and there is also enough user data space allocated.
    if Assigned(UserData) then
      if FNodeDataSize >= 4 then
      begin
        NodeData := Pointer(PByte(@Result.Data) + FTotalInternalDataSize);
        NodeData^ := UserData;
        Include(Result.States, vsInitialUserData);
      end
      else
        ShowError(SCannotSetUserData, hcTFCannotSetUserData);
...
end;

P.S. Компонент - VirtualTreeview (вроде 4.4)
PM MAIL   Вверх
xvr
Дата 2.10.2010, 21:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(GydruS @  2.10.2010,  17:43 Найти цитируемый пост)
P.S. Компонент - VirtualTreeview (вроде 4.4) 
С этого и надо было начинать - стандартные VCL компоненты не занимаются выделением памяти под ObjectData. 

Цитата(GydruS @  2.10.2010,  17:43 Найти цитируемый пост)
Выделять память под TNodeData не надо. DirectoryTreeView это делает сам (как и освобождает память).
И нужные конструкторы и деструкторы вызывает? Не верю!
Ваш TNodeData включает поле с конструктором и деструктором (AnsiString Name), попытка сделать копию такой структуры (через копирование памяти) с последующим удалением оригинала (что у вас и было в 1м варианте) приведет к ошибке - AnsiString удалит строку, которую содержал, т.к. он не в курсе, что с него сняли 'копию' (что опять же вы и наблюдали)

Цитата(GydruS @  2.10.2010,  17:43 Найти цитируемый пост)
Баг был там. 
Бага не нашел - все законно. И копирования структуры UserData тоже не нашел. Вы уверенны, что компонент аллокировал память и копировал структуру?



PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.0623 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.