Что делать с ошибками «Ошибка создания дескриптора окна» в приложении C #? - PullRequest
4 голосов
/ 07 февраля 2009

Я уже посмотрел на этот вопрос , и я уже проверил предложения, которые были сделаны там. Моя программа создает и уничтожает множество элементов управления пользовательского интерфейса ( много элементов управления пользовательского интерфейса), и все, что заставляет элементы управления зависать после их «разрушения», вызовет эту проблему. (Интересный факт: если вы не установите для свойства ToolStrip элемента управления Visible значение false, прежде чем уничтожить его контейнер, он не удаляется, поскольку он все еще зарегистрирован в Windows для получения событий изменения темы; он только отменяет регистрацию само по себе, когда его не видно, и у него, очевидно, нет никакого способа узнать, что это происходит, когда его контейнер разрушается.)

Дело в том, что на самом деле возможно, что мое приложение действительно работает без оконных дескрипторов. Программа имеет единую форму, которая имеет вложенные элементы управления вкладками. Каждая родительская вкладка имеет 12 или 13 дочерних вкладок, а дочерняя вкладка может иметь 30 или 40 элементов управления. Для пользователя вполне возможно иметь 15 родительских вкладок, открытых в любой момент времени, и это становится частью более 5000 живых элементов управления в приложении. И я знаю, что многие из моих элементов управления используют более одного дескриптора окна.

(И прежде чем вы скажете: «Ну, похоже, вы неправильно спроектировали пользовательский интерфейс», позвольте мне не обращать на это внимания: причина, по которой приложение существует в первую очередь, заключается в том, что пользователи имеют огромное пространство данных, которые они должны быть в состоянии быстро перемещаться. В действительности, вкладки внутри вкладок действительно работают для них.)

Насколько я понимаю, существует жесткое ограничение в 10 000 оконных дескрипторов на приложение. Если это действительно так (я понимаю, что многие вещи не соответствуют действительности), тогда мне придется управлять их использованием в своем приложении. Например, я могу выбросить содержимое наименее недавно использованной вкладки, когда у меня заканчиваются дескрипторы окон.

Но как мне узнать, что у меня закончились оконные ручки? И действительно ли это правильный подход к проблеме?

(Это одна из многих причин, по которым я хотел бы перестроить этот интерфейс в WPF.)

Ответы [ 3 ]

3 голосов
/ 07 февраля 2009

Лучший подход - уменьшить количество ручек, а не реагировать на достижение предела процесса. Это обеспечит лучшую производительность и (на мой взгляд) будет более надежным.

Вы знакомы с тем, как работает большинство элементов управления сеткой? Сетка может иметь очень большое количество ячеек, но элемент управления сеткой не создает поле редактирования (элемент управления) для каждой ячейки. Существует только одна коробка редактирования, и она перемещается по мере необходимости; если ячейка представляет собой поле со списком (раскрывающийся список), то создается и перемещается одно поле со списком; и т. д. Это означает, что вам нужно нарисовать что-то похожее на нужный элемент управления, но вам нужен только один (каждый) элемент управления в реальном использовании.

Аналогично, некоторые элементы управления вкладками используют одно окно / элемент управления вместо создания одного окна для каждой вкладки.

Я бы посоветовал рассмотреть такие приемы, чтобы уменьшить ваш контрольный счет.

1 голос
/ 11 февраля 2009

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

Краткий ответ:

  1. Поддерживать LRU-кеш вкладок, которые обновляются при каждом посещении пользователем.
  2. Подсчитайте количество используемых дескрипторов окон перед созданием новой вкладки.
  3. Если используется слишком много дескрипторов окон, утилизируйте содержимое наименее недавно посещенных вкладок, пока количество используемых дескрипторов окон не опустится до безопасного уровня.
0 голосов
/ 07 февраля 2009

Вы можете использовать безоконные элементы управления - для этих типов элементов управления окно не требуется. Приложения, разработанные так, чтобы иметь много элементов управления в окне, должны быть разработаны для использования элементов управления без окон. Посмотрите, например, Internet Explorer - посмотрите на него в Spy ++ - вы увидите на удивление мало окон с тем, сколько элементов управления он отображает.

Один забавный факт, который мы обнаружили при переходе на .Net, заключается в том, что у окон есть сходство с потоками, и вы должны уничтожить их в этом потоке - так что если вы просто оставляете это для сборки мусора (которая выполняется в другом потоке) для очистки до вашего контроля, тогда окна не будут разрушены. Поэтому в ваших элементах управления, имеющих окна, реализуйте IDisposable и уничтожайте их явно.

Вы можете увидеть, сколько объектов GDI существует в вашем приложении, используя диспетчер задач, проводник процессов, perfmon и т. Д. Дескрипторы окон - это объекты GDI, поэтому, если вы увидите, что это число возрастает до тысяч, вы знаете, у вас возникнут проблемы.

...