Delphi 2009, всплывающее меню вызывает EStackOverFlow - PullRequest
2 голосов
/ 10 апреля 2011

маленький кусочек стека

:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:0043797f TFont.SetData + $2F
:00437d92 TFont.SetStyle + $36
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:004378c5 TFont.Assign + $61
:004bf1f0 TThemedMenuItem.CalcBounds + $68
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:0043797f TFont.SetData + $2F
:00437d92 TFont.SetStyle + $36
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:004378c5 TFont.Assign + $61
:004bf1f0 TThemedMenuItem.CalcBounds + $68
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:0043797f TFont.SetData + $2F
:00437d92 TFont.SetStyle + $36
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:004378c5 TFont.Assign + $61
:004bf1f0 TThemedMenuItem.CalcBounds + $68
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:0043797f TFont.SetData + $2F
:00437d92 TFont.SetStyle + $36
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:004378c5 TFont.Assign + $61
:004bf1f0 TThemedMenuItem.CalcBounds + $68
:004b9839 TCustomActionControl.CMFontChanged + $1D
:0047fe17 TControl.Perform + $27
:0047eb54 TControl.FontChanged + $40
:0043797f TFont.SetData + $2F
:00437d92 TFont.SetStyle + $36
:004bb1d7 TCustomActionControl.CMTextChanged + $1F
:004801f1 TControl.WndProc + $2D5
:0047fe17 TControl.Perform + $27
:0047ded6 TControl.SetTextBuf + $22
:004ba9df TCustomActionControl.SetActionClient + $C7
:004b6aa7 TCustomActionBar.CreateControl + $D3
:004a8b6f TCustomActionMenuBar.CreateControl + $B
:004bdbee TCustomActionDockBar.CreateControls + $A
:00481779 TControl.WMContextMenu + $121

и он продолжается и продолжается ...

последний выполненный код, который я сгенерировал, изменил одну из надписей меню.

ОБНОВЛЕНИЕ: я проследил исходный код, и строка, в которой он обналичил это

procedure TPopupActionBar.Popup(X, Y: Integer);
...
FPopupMenu.RecreateControls;//crash here
FPopupMenu.Popup(X, Y);

, однако есть рекурсивный вызов строки ниже.и собираюсь бросить модуль actnPopup.pas, я не могу найти хвост рекурсивного вызова.

это существующий код, который работал и хорошо компилировался в более старой версии Delphi.После того, как новый ManuPop был создан и заменен старым, он работает хорошо.Тем не менее, дизайн потерян, так как в оригинале было больше возможностей.

По-прежнему не в курсе.

больше обновлений: что-то еще более странное, когда я запускаю код на своей машинекомпилятор), он падает и горит, а на другом компьютере (пользовательский компьютер) запускается с радугой и бабочками.я не понимаю!

Ответы [ 2 ]

4 голосов
/ 10 апреля 2011

Общие рекомендации

Это проблема рекурсии.
Из стека вызовов обратите внимание, что каждый раз происходит одна и та же последовательность.
Это означает, что что-то заставляет код вводить метод из самого себя, даже если это косвенно.

:0047fe17 TControl.Perform + $27 
:0047eb54 TControl.FontChanged + $40 
:0043797f TFont.SetData + $2F 
:00437d92 TFont.SetStyle + $36 
:004b9839 TCustomActionControl.CMFontChanged + $1D 
:0047fe17 TControl.Perform + $27 
:0047eb54 TControl.FontChanged + $40 
:004378c5 TFont.Assign + $61 
:004bf1f0 TThemedMenuItem.CalcBounds + $68 
:004b9839 TCustomActionControl.CMFontChanged + $1D 

Следующий простой код иллюстрирует ту же проблему:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1Click(Sender);
end;

В общем, можно просто установить точку останова и выяснить, почему метод реентерабельный . Обычно это потому, что:

  • Рекурсия преднамеренная, но есть ошибка, препятствующая выполнению условия завершения.
  • Или рекурсия является непреднамеренным побочным эффектом кругового «триггерного» поведения. То есть Объект B меняет свое состояние в ответ на изменение в Объекте A, и наоборот. Так что события в А и Б продолжают вызывать друг друга.
  • Неправильное использование Windows Message Architecture. Будьте очень осторожны с Application.ProcessMessages. Это очень опасный метод для использования, потому что он может вызвать повторный ввод в код с середины задачи / процесса - в отличие от следующей итерации цикла сообщений Windows.

Эта специфическая проблема

Конечно, при просмотре стека это выглядит как стандартный код Delphi, рекурсивно вызывающий сам себя. Но одна из опасностей разработки RAD заключается в том, что установка значений свойств является формой написания кода - даже если это не так.
Возможно, что конкретное значение свойства может привести к тому, что часть кода будет вести себя немного по-другому, вызывая тем самым рекурсию.

К сожалению, недостаточно информации для разностного решения, но я могу предложить предложения по проверке:

  • Конечно, компиляция с отладочными dcu может помочь отследить проблему. Не пугайтесь перспективного чтения исходного кода VCL - на самом деле это один из лучших способов обучения.
  • Вы добавили какие-либо элементы управления действиями?
  • Используете ли вы какие-либо сторонние компоненты?
  • Есть ли разница между тем, отображается ли всплывающее меню в данный момент или нет?
  • Я заметил, что вызывается метод FontChanged, но изменение заголовка не должно вызывать это.
  • Если вы используете какие-либо дополнительные компоненты, которые будут взаимодействовать с PopupMenu, попробуйте удалять или отключать их по одному.
  • Попробуйте сбросить свойства до их значений по умолчанию. Это можно сделать, просматривая dfm как текст. Большинство значений свойств, которые вы видите в dfm, будут значениями не по умолчанию. Простое удаление строки вернет ее к значению по умолчанию.

Если вы все еще боретесь

Вы можете предоставить некоторую дополнительную информацию, чтобы помочь:

  • Пример кода, который устанавливает заголовок, включая событие, которое его запускает.
  • Обработчики событий для всплывающего меню
  • и любые элементы управления действиями, которые взаимодействуют с меню.
  • DFM как текст соответствующих элементов управления.
1 голос
/ 10 апреля 2011

Типичная причина чего-то вроде этого - обработчик события, который выполняет какое-то действие, которое запускает тот же обработчик события. Отсюда бесконечная рекурсия и возникающее в результате переполнение стека. С большой вероятностью это ваша проблема.

Чтобы разобраться, я бы оглянулся назад к основанию стека вызовов и выяснил, где он начинает повторяться. Там должны быть подсказки.

...