На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> про хэндл значка и LoadImage , Когда разрушается значок, загруженный с флагом shared и можно ли узнать, валиден ли хэндл?
    Здравствуйте!

    Хочу, на C++ сделать класс обёртку для значка. Не собираюсь реализовывать весь функционал, лишь необходимый мне минимум.
    Со значками, я раньше не связывался. Знакомство весьма поверхностное.

    Есть функция LoadIcon(), которую рекомендуется заменить LoadImage().

    Функция LoadImage() загружает значок и возвращает мне хэндл. Который почему-то типа HANDLE., а иконка должна быть типа HICON. Имею ли я право использовать приведение типов?

    Как сказано в мане, если задать флаг LR_SHARED, хэндл копируется. А значок будет уничтожен, когда он перестанет быть нужным.

    Ещё в мане сказано, что значок нужно разрушать, когда он не нужен, функцией DestroyIcon().

    Так вот, я не очень уверен:
    в каких случаях мне надо вызывать DestroyIcon()?
    и есть ли возможность проверить действительность значка?

    ExpandedWrap disabled
      class icon
      {
      public:
       
       
      // конструктор
      icon( HMODULE hModule, LPCTSTR strName, INT cx, INT cy, UINT flags ):
      _handle( NULL )
      {
      _handle = ::LoadImage( hModule, strName, IMAGE_ICON, cx, cy, flags );
      }
       
       
      // деструктор
      ~icon()
      {
      ::DestroyIcon( _handle );
      }
       
       
      // возвращает хэндл значка
      HICON handle() const
      {
      return reinterpret_cast< HICON >( _handle );
      }
       
       
      private:
       
      // хэндл
      HANDLE _handle;
       
      };


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

    Когда значок разрушать? Всегда, или только в особых случаях?

    А если я загружу стандартный значок, с флагом LR_SHARED, потом его хэндл задам в оконном классе, всё равно звонить в DestroyIcon()?
    Сообщение отредактировано: Eric-S -
      Цитата
      Функция LoadImage() загружает значок и возвращает мне хэндл. Который почему-то типа HANDLE., а иконка должна быть типа HICON. Имею ли я право использовать приведение типов?

      Да, но есть один момент, иногда результат при LoadImage получается не совсем тот что ты хочешь видеть, так как нужно задавать параметры явно.

      Ну на соответствующие вызовы IMAGE_BITMAP, IMAGE_CURSOR, IMAGE_BITMAP нужно вызывать соответствующие DeleteObject, DestroyCursor, DestroyIcon.

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

      Когда значок разрушать? Всегда, или в особых случаях?

      Нет не всегда, если ты создал локальный класс в функции и значек этого класса присвоил какой нибудь кнопке, то при разрушении объекта в деструкторе удалил значек, то долго будешь гадать почему он не отображается на кнопке.

      Цитата
      Как сказано в мане, если задать флаг LR_SHARED, хэндл копируется. А значок будет уничтожен, когда он перестанет быть нужным.

      Нет там говориться, что значек будет загружен один раз, а при повторной загрузке, создастся новый хэндл ссылающийся уже на загруженный значек. Ну соответственно если ты удалишь значек по первому хэндлу то второй хэндл станет не валидным.
        Цитата Dem_max @
        Нет там говориться, что значек будет загружен один раз, а при повторной загрузке, создастся новый хэндл ссылающийся уже на загруженный значек. Ну соответственно если ты удалишь значек по первому хэндлу то второй хэндл станет не валидным.

        А если быть ещё более точным, то при использовании флага LR_SHARED все вызовы LoadImage() будут возвращать один и тот же хендл, а система будет увеличивать внутренний счётчик ссылок. При удалении такого значка, нужно чтобы DestroyIcon() была вызвана столько же раз, сколько и LoadImage(), чтобы значок был действительно удалён.
          Цитата artsb @
          А если быть ещё более точным, то при использовании флага LR_SHARED все вызовы LoadImage() будут возвращать один и тот же хендл, а система будет увеличивать внутренний счётчик ссылок. При удалении такого значка, нужно чтобы DestroyIcon() была вызвана столько же раз, сколько и LoadImage(), чтобы значок был действительно удалён.

          Значит, без зависимости от флага DestroyIcon() нужно вызывать всегда, на каждый вызов LoadImage()?

          Добавлено
          Цитата Dem_max @
          Ну на соответствующие вызовы IMAGE_BITMAP, IMAGE_CURSOR, IMAGE_BITMAP нужно вызывать соответствующие DeleteObject, DestroyCursor, DestroyIcon.

          Это-то понятно. Я сразу, в примере обозначил, что класс для значка и тип определён жестко - IMAGE_ICON

          Добавлено
          Цитата Dem_max @
          Нет не всегда, если ты создал локальный класс в функции и значек этого класса присвоил какой нибудь кнопке, то при разрушении объекта в деструкторе удалил значек, то долго будешь гадать почему он не отображается на кнопке.

          Я собираюсь данный объект, держать, пока работает окно.
          К примеру передать хэндл значка оконному классу и значку в системном трее.

          А когда программа будет завершатся, деструктор автоматически разрушит значок.

          Но я очень часто встречал в примерах, код:
          ExpandedWrap disabled
            wcex.hIcon = LoadIcon( MAKEINTRESOURCE( RES_ICON ) );
            auto atom = RegisterClassEx( &wcex );


          И всё. Типа значок должен будет автоматически разрушен.
            сделай в своём классе метод Detach(), который укажет деструктору класса не прибивать хендл
              Цитата ElcnU @
              сделай в своём классе метод Detach(), который укажет деструктору класса не прибивать хендл

              Это понятно и сделать можно.

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

              К примеру, в классе окна, я сделал что-то вроде:
              ExpandedWrap disabled
                // деструктор
                window::~window()
                {
                 
                if( NULL != _handle )
                {
                if( ::IsWindow( _handle ) )
                {
                 
                // разрушить окно
                ::DestroyWindow( _handle );
                }
                }
                }
                Цитата Eric-S @
                К примеру, в классе окна, я сделал что-то вроде:

                а зачем аж 2 проверки предварительно? DestroyWindow и без тебя всё узнает....
                  Цитата Eric-S @
                  Но я очень часто встречал в примерах, код:
                  ExpandedWrap disabled
                    wcex.hIcon = LoadIcon( MAKEINTRESOURCE( RES_ICON ) );
                    auto atom = RegisterClassEx( &wcex );


                  И всё. Типа значок должен будет автоматически разрушен.

                  MSDN:
                  Цитата
                  The system automatically deletes these resources when the process that created them terminates; however, calling the appropriate function saves memory and decreases the size of the process's working set.
                  Т.к. окно будет жить на всём протяжении работы программы, то можно и не удалять этот значок вручную. Об этом позаботится система.
                    Цитата ElcnU @
                    а зачем аж 2 проверки предварительно? DestroyWindow и без тебя всё узнает....


                    Но почему-то не узнаёт.

                    Да, одну проверку можно бы и сократить. Осталась по историческим причинам.

                    А вот если проверки убрать, то дестроер, возбуждает исключения. У меня же на системные функции, сделаны обёртки с проверкой ошибки.

                    В деструкторе вызывается метод destroy(). Который с большой вероятностью стрельнёт исключением.
                    Вот отсюда и проверки. Пусть даже излишние.
                    Подумаешь, несколько тактов потеряю. Но получу более стабильный и надёжный код.

                    ExpandedWrap disabled
                      class window:
                      public std::enable_shared_from_this< window >
                      {
                      public:
                       
                       
                      // деструктор
                      virtual ~window()
                      try
                      {
                       
                      dispose();
                      }
                      catch( ... )
                      {
                      std::terminate();
                      }
                       
                       
                      // освобождает ресурсы
                      void dispose()
                      {
                      if( is_create() )
                      {
                      destroy();
                      }
                      }
                       
                       
                      // подтверждает, что окно создано
                      bool is_create() const
                      {
                      return IsWindow( _handle )? true: false;
                      }
                       
                       
                      // разрушает
                      void destroy()
                      if( FALSE == DestroyWindow( _handle ) )
                      {
                      throw std::system_error( GetLastError(), std::system_category(), "DestroyWindow" );
                      }
                      _handle = NULL;
                      }
                       
                       
                      private:
                       
                      HWND _handle;
                       
                      };


                    Ну и как-то так юзаю.

                    ExpandedWrap disabled
                      auto form1 = std::make_shared< window >();
                       
                      form1->create( ... );
                       
                      // application::run();
                       
                      form1->dispose();


                    Тут всё пока нормально. А вот если закоментировать строчку с вызовом create() или добавить цикл обработки сообщений, где в оконной процедуре, так же вызывается DestroyWindow. То всё, метод destroy() обязательно, стрельнёт исключением. Поскольку хэндл не действителен. И окно уже давно разрушено или даже не создано.

                    Добавлено
                    Цитата artsb @
                    будет жить на всём протяжении работы программы, то можно и не удалять этот значок вручную. Об этом позаботится система.


                    Система освобождает хэндл, когда программа завершается.

                    А ведь система и память из кучи освобождает. Зачем вызывать HeapFree() после того как блок полученный HeapAlloc(), был использован?

                    Да, в частном случае, на лишние функции можно забить.

                    А по мне, если есть неуправляемый ресурс. Его нужно засунуть в класс. И пользовать соответствующие объекты. Пускай за своевременным освобождением ресурсов, забодится объект.
                    Сообщение отредактировано: Eric-S -
                      Цитата Eric-S @
                      Тут всё пока нормально. А вот если закоментировать строчку с вызовом create() или добавить цикл обработки сообщений, где в оконной процедуре, так же вызывается DestroyWindow. То всё, метод destroy() обязательно, стрельнёт исключением. Поскольку хэндл не действителен. И окно уже давно разрушено или даже не создано.

                      то что DestroyWindow вернула FALSE еще не означает конец света.... ну вернула, да вернула, просто внутри проверка сказала, что хендл кривой.... какая разница где это скажется, у тебя в классе или в где то там в user32.dll, факт тот, что даже без твоего участия эта проверка есть, так нафига тебе еще что то проверять, да исключения генерить? Что бы необоснованно отхавать процессорного времени? Ну дело личное конечно
                        Цитата ElcnU @
                        то что DestroyWindow вернула FALSE еще не означает конец света.... ну вернула, да вернула, просто внутри проверка сказала, что хендл кривой....

                        Я вообщем-то согласен, что моя проверка дублирует, внутреннюю проверку из функции DestroyWindow.

                        Но, когда я вызываю метод destroy, моей проверки нет. По сути, это просто обёртка для DestroyWindow() и проверка ошибки.

                        Проверка есть в методе dispose(). Но он, реализует подстраховочное освобождение. Предполагается, что окно было уже разрушено явным вызовом метода destroy(). Соответственно, в генеральной линии, я наоборот экономлю ресурсы машины.

                        Ну, а ежели что-то пошло наперекосяк, последней линией становится деструктор. Который выполняет дополнительный контрольный вызов метода dispose().

                        Не вижу смысла, особо заниматся оптимизацией, резервного механизма освобождения ресурсов.


                        Кроме того, моя проверка, использует задокументированные функции. Ежели я попытаюсь использовать внутреннюю проверку, вшитую в DestroyWindow(), которая не задокументирована. То могу огрести дополнительные проблемы. По этому, если DestroyWindow() сообщает о некой внутренней ошибке, проще бросить соответствующее исключение.

                        Конечно, я в деструкторе, вместо вызова dispose() могу вызывать напрямую DestroyWindow(). Забив на все проверки, исключения, перехват исключений, обнуление хэндла. И прочее, что там наверчено. Но в этом случае, я буду уже дублировать свои механизмы.
                        А может я захочу в будущем, в метод destroy(), воткнуть ещё вызов on_destroy_handle(). А в деструкторе забуду про это?

                        Этот механизм, у меня, реализован уже давно, и я не замечал за ним, проблем, в момент разрушения окна. И даже наоборот. Он сформировался таким из-за внешних обстоятельств.
                        К примеру UnregisterClass() раньше ругалась, что окно не разрушено и класс всё ещё используется.

                        Но это всё офтоп. Я просто привёл пример, как проверяю действительность хэндла окна. И для чего мне это нужно.

                        Хотелось бы, сделать нечто подобное, для хэндла значка. Может быть не совсем так.
                        Но думаю, будет неприятно, если я лишний раз вызову DestroyIcon().
                          Цитата Eric-S @
                          Проверка есть в методе dispose(). Но он, реализует подстраховочное освобождение. Предполагается, что окно было уже разрушено явным вызовом метода destroy(). Соответственно, в генеральной линии, я наоборот экономлю ресурсы машины.


                          Цитата Eric-S @
                          ExpandedWrap disabled
                            return IsWindow( _handle )? true: false;

                          так будет экономичней
                          ExpandedWrap disabled
                            return (_handle!=NULL);

                          все равно хендл обнуляется

                          Цитата Eric-S @
                          К примеру UnregisterClass() раньше ругалась, что окно не разрушено и класс всё ещё используется.

                          не вижу смысла в вызове этой функции... соответстенно все её ругательства тоже бессмыслены


                          Цитата Eric-S @
                          Но думаю, будет неприятно, если я лишний раз вызову DestroyIcon().

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


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0914 ]   [ 16 queries used ]   [ Generated: 27.04.24, 09:26 GMT ]