Перейти к содержанию

Antonshka

Пользователи+
  • Постов

    410
  • Зарегистрирован

  • Посещение

  • Победитель дней

    16

Весь контент Antonshka

  1. Не знаю, хорошо ли это, писать сейчас на форуме. Ведь форум сейчас на компьютере у @Xipho, плюс никто не пишет ничего чего-то, плюс форум как я понял будет скоро закрыт. Однако, напишу все же, раз тему завел. Да простят меня все. Я лишь хотел сказать, что я закончил с этой таблицей акселератора. И для тех кому интересно, реализовал я ее так. Это пример того как создается главное окно, создается меню, назначаются горячие клавиши. Это главный messageLoop Это translateAccelerator А это классы для работы самодельного аккселератора. Кое-какой функционал будет еще добавлен для них. Keystroke.h И Keystroke.cpp
  2. Antonshka

    Custom Keyboard Accelerators

    Привет, с наступившим Новый Годом🌲! Хорошо его провести. Кто-нибудь игрался с самодельной таблицей акселераторов? Как известно, стандартная WinAPI таблица акселераторов поддерживает только одну нажатую клавишу, совместно с SHIFT, CONTROL, или ALT. Например, позволено делать только так, - "SHIFT + ALT + M", или "ALT + G". Но что если нужно так, "SHIFT + ALT + M + A + T"? У меня дело дошло до горячих клавиш для пунктов меню. Текст то выводится, а про саму реализацию клавиш я и забыл. Сейчас думаю как реализовать самодельную таблицу. В основном цикле сообщений будет своя функция translateAccelerator Далее, в этой функции (translateAccelerator), нужно сделать обход по всем виджетам. Для тех виджетов, чей список горячих клавиш непустой, сделать проверку, на совпадение. Список горячих клавиш думаю будет таким - Если проверка на совпадение покажет, что такие клавиши для этого виджета установленны, то будет послано сообщение, этому виджету - Осталось придумать как эффективнее проверять клавиши. Как вообще отслеживать последовательность нажатых клавиш.
  3. С наступающим Новым Годом всеееех!
  4. Стимул обычно увеличивается словами поддержки. Например, - "потерпи, со временем ты это освоишь, и я проходил через подобные трудности". Слова же, - " возможно, это не твое, ведь слесарю слесарево", как бы дают понять, - "возможно, твой ум не в состоянии постичь такое, возможно, тебе не стоит этим заниматься". Такие слова только уменьшают стимул. Не видишь ли недоброжелательность, вместо увеличения стимула, уменьшать его? Но, как я уже сказал, на меня эти слова не подействовали. Я уже не новичок, - путь определенный я уже проделал, и способности свои я уже узнал. Вопрос к нему был не про положительную сторону.
  5. Как я вижу, @Alex2411 не чернит ресурс, но говорит по факту. Ему @Xipho задал конкретный вопрос, он дал ему конкретный ответ. Указал на недоброжелательность. Такую недоброжелательность я лично ощутил и на себе. Правда лично меня эти слова никак не задели. К моему удивлению. Недоброжелательность на форуме была, этот факт. Недоброжелательность не способствует развитию форума, это тоже факт. @Alex2411 просто указал на эти факты. А что касается доброжелательности, и пользы от форума, - ее конечно было несказанно больше. Я не думаю что активность форума мала из-за недоброжелательности. Она была крайне редка. В сравнении с доброжелательностью.
  6. Может быть тебе это не доставляет удовольствие. Может быть дело вовсе не в отсутствии времени. Есть уникальная по своей силе фраза "Кто хочет, ищет возможности, кто не хочет, ищет причины". Лучше этой "лакмусовой бумажки" я ничего еще не встречал. Она раскрывает истинные намерения человека на 200 процентов. Раскрывает всегда. Если человек говорит тебе слова оправдания, вместо того чтобы заботиться о поиске путей решения, - значит ему этого просто не хочется. Ему это не доставляет удовольствие. Человек не делает того, что ему не доставляет удовольствие. И чтобы не обидеть другого человека, или по какой иной причине, он, вместо признании в этом, признании в отсутствии хотения, говорит как-бы уклончиво. Активности на форуме практически нет, естественно это должно доставлять автору некоторые неудовольствия. Умножим это на то, что такое положение вещей наблюдается уже в течении 10 лет. Итак, человек, который поставил мне недоумевающий смайлик, в сообщении о поддержке закрытии форума? Чего тебе не понравилось? Не хочет @Xipho получать неудовольствие, хочет получать удовольствие. Я его в этом поддержал. За что такой смайлик? За то ли, что для тебя закрытие форума не выгодно? Впрочем, не важно, за что такой смайлик. @Xipho человек взрослый, решение свое он обдумал. Я поступил бы также как он, я пошел бы тратить свое время в пользу своего удовольствия.
  7. Я поддерживаю. Форум нужно закрывать. Общаются в основном всего несколько человек. Их можно сосчитать по пальцам. Я рад, что @Xipho решился на это! Не подумайте, что я против форума. Я за появление свободного времени у @Xipho.
  8. Идея с std::unordered_map простая. Все объекты PopupMenu хранятся в unordered_map. У каждого объекта PopupMenu есть специальное поле, которое есть его ключ в unordered_map. Этот ключ уникальный, его тип INT. Указатель же на сам объект хранится как значение в unordered_map. То есть, unordered_map(Key, Value) = unordered_map(INT, PopupMenu*) При сохранении объектов из unordered_map в файл на диск, сохраняется также и это поле-ключ, у каждого объекта. При следующем запуске приложения, значение Value(PopupMenu*) уже будет другое, но ключ будет тот-же самый. Поэтому при считывании файла, нужно будет только сверить ключи. Посмотрю про protobuf. Интересно, что это. Спасибо. Архитектура библиотеки со дня ее создания почти не изменилась. Она меня устраивает. Большой и постоянный рефакторинг основан на постоянном увеличении опыта и знаний. А также и идей. Конечно, было бы интересно посмотреть как пишут программы специалисты, поучиться у них. Кое-какой план все же есть. У меня есть блокнот, в котором я пишу задания. Например, - сделать нужно то-то и то-то, это нужно удалить, это добавить, над этим подумать.
  9. Что-то @Xipho не ответил. Возможно времени нет у него. В любом случае, с сериализацией/десериализацией я закончил. Основа этого дела, это использование std::unordered_map. Ключ используется для выбора правильного объекта. Строки сохраняются в файл на диск так, - сперва сохраняется длина строки, затем ее содержимое. При считывании строки с файла на диске, сперва считывается длина строки, затем идет проверка этой длины на ноль, затем, если длина не равна нолю, считывается содержимое строки. Буфер для строки нужно предварительно увеличить. Теперь можно заняться улучшайзенгом кода. Превращением его из каши во что-то более понятное. А то @Xipho, увидев его, потеряет сознание. Прошел год, (365 дней), а я написал только PopupMenu, MainMenu, ToolTip, и TitleBar (в форме кода-каши). Ай да молодец я.
  10. Везде говорят про 4096 байта. У тебя нет ссылки на это стандарт?
  11. Что если поле класса std::wstring? Плюс этот странный sizeof. Такое странное поведение sizeof основано на Data structure alignment.
  12. Менять весь интерфейс запущенного приложения конечно захочет не каждый. Это на выбор, при активированном режиме.
  13. Появилась хорошая идея, как сохранить/восстановить объекты PopupMenu. Раньше PopupMenu назначалось контроллу по указателю. Теперь будет так
  14. Представь себе главное меню какого-либо приложения. Первый элемент такого меню обычно называется Файл. Нажимая на него, появляется PopupMenu. В этом PopupMenu обычно следующие названия пунктов, - Открыть, Сохранить, Сохранить как, Выход, и т.п. Пункт Открыть вызывает к примеру функцию VOID Open(), - так предусмотрел разработчик. Однако, пользователь, по желанию разработчика, может активировать режим модификации. Он, пользователь, включив такой режим, открывает этот PopupMenu, где Открыть, Сохранить, Сохранить как, Выход, затем, кликает по нему правой кнопкой мыши, перед ним появляется другое PopupMenu, над этим PopupMenu. Это второе PopupMenu, имеет пункты со следующими названиями, - Изменить название пункта, Изменить опцию пункта (то есть функцию), и другие. Выбрав Изменить опцию пункта, появляется окно со списком (ListView например, или TreeView). В нем перечислены все (дозволенные) существующие опции/функции, одну из которых можно назначить на этот пункт. Например, есть функция VOID SaveAs() для пункта Сохранить как. Пользователь может выбрать ее из списка и назначить на пункт Выход. Это просто пример. Так вот, текущая задача, - это сериализация/десериализация этого указателя на функцию VOID SaveAs(). Так чтобы она теперь была для пункта Выход. Даже после перезапуска приложения. Частично это задача теперь уже решена, если даже не полностью - Это поле класса PopupMenu. inline static std::map<std::wstring, OnClickForItemOfPopupMenu> userClickFunctionsForItems; Разработчик заполняет этот std::map, определяя тем самым для пользователя допустимые варианты выбора опций. WGW::PopupMenu::userClickFunctionsForItems.insert(std::make_pair(L"Открыть", open)); //open, это указатель на VOID open() WGW::PopupMenu::userClickFunctionsForItems.insert(std::make_pair(L"Параметры", showParameters)); //showParameters, это указатель на VOID showParameters() WGW::PopupMenu::userClickFunctionsForItems.insert(std::make_pair(L"Копировать", copy)); //copy, это указатель на VOID copy() Пользователь, в ListView контролле, выбирает либо Открыть, либо Параметры, либо Копировать. Выбрав например Параметры, это слово сохраняется в поле userItemClickFunction класса Item. Все, переназначение опции/функции для конкретно этого пункта совершено. Новая функция вызовется через следующее выражение одного их методов класса PopupMenu, при клике по пункту. userClickFunctionsForItems.at(item->originalItem->userItemClickFunction)(&onClickEventForItemOfPopupMenu); item->originalItem->userItemClickFunction //userItemClickFunction это std::wstring равное Открыть, Параметры, или Копировать, смотря что выбрал пользователь. Это дело с указателем сейчас работает нормально. Для сериализации/десериализации нужно по идее просто сохранить/восстановить это поле со строкой - userItemClickFunction класса Item. Сейчас нужно придумать сохранение/восстановление объектов PopupMenu. Плюс их правильное назначение для контроллов, после восстановления.
  15. Я вернулся к написанию библиотеки GUI. Казалось бы, самодельная система PopupMenu уже закончена, но нет, мне пришла странная идея сделать её лучше чем в QT, - больше функционала, больше гибкости. PopupMenu на любой вкус и цвет. Причем для этого абсолютно не придется менять что-то в классе, - меняй только открытые свойства. И это идея удалась, - благодаря всем нам конечно. Система PopupPenu, а с ней и система MainMenu, получились ну реально крутые. Дело дошло до того, что была организована интерактивная замена PopupMenu'ек и их итемов в режиме реального времени. Как например в FireFox, когда можно мышкой ухватить итем какой-либо закладки в PopupMenu, и перетащить в другой PopupMenu. Причем создается такое окно-отрывок (snippet), с итемом на нем. Конечный пользователь может сам создать новое PopuMenu, новый итем. Также пользователь может изменить Click-функцию для итема, например выбрав из выпадающего списка нужную опцию, нужную функцию для этого конкретного итема. Говоря короче, конечный пользователь (здесь это тот кто запустит уже готовый exe) может сам настроить под себя всю систему MainMenu и PopupMenu, - если разработчик позволит ему так делать, например добавив чек-бокс, для активации режима модификации. Для сохранения всех переделок, сделанных конечным пользователем, нужна сериализация/десериализация. Я поторопился, - интерактивная система была создана раньше системы сериализации. Хотя, когда только все начиналось, какое-то представления, как эту сериализацию потом организовать, у меня все-таки было. Но сейчас, я не могу вспомнить, что я там напланировал. В любом случае, рано или поздно, эта система сериализации будет создана.
  16. Привет, привет, любители логических задач! У меня снова есть для вас кое-что странное. В коде приложения, определен класс Sample. Также, в коде приложения определены три его объекта-экземпляра, А, B, и C. Класс Sample имеет одно единственное поле PTR, - указатель на функцию. Это поле по умолчанию равно nullptr. В коде приложения есть множество разных функций. Сигнатуры этих функций совпадают с типом PTR. Запускаем приложение! Наша единственная задача в приложении, - назначить для поля PTR объектов A, B, и C, свой указатель на какую-либо функцию. После назначения, мы закрываем приложение. Приложение должно сохранить назначенные указатели на диск. При следующем запуске приложения, оно, приложение, найдя файл сохранения, прочитает его, и восстановит значения полей объектов А, B, и C. Но это еще не все. Мы можем захотеть создать еще несколько объектов динамически, повторив с ними тоже, что было сделано с объектами А, B, и C. И теперь, приложение должно при закрытии сохранить еще и динамически созданные объекты, плюс и их поля. Как вам такой сюжет?
  17. Спасибо за советы. Почитал, для тех кому тоже интересно, вот выписка -
  18. Если суммировать, то получается, самая лучшая формула создания потока, его завершения, а также выгрузки DLL, на С++, это - поток всегда создается через _beginthreadex - поток всегда завершается сам, выходя через свой return - FreeLibraryAndExitThread никогда не вызывается - выгрузкой библиотеки, через FreeLibrary, занимается стороннее приложение/процесс. Как вариант, тот же, который и загрузил её. Эта формула, актуальна для того случая, когда DLL, загружается в процесс каким-то сторонним процессом, и эта загруженная DLL, через какое-то время, должна быть выгружена, оставив процесс, в который она была загружена, запущенным. Когда же процесс сам лично загружает DLL, то там немного другая история, и ее, по крайней мере я, здесь не рассматривал.
  19. Я ждал этот вопрос. Пока нет, но когда они могут появиться, я не хочу возвращаться и переписывать с CreateThread на _beginthreadex. Плюс, я не могу знать, вызывают ли те WinAPI функции или не WinAPI функции, которые я могу использовать, внутренне CRT функции. Или вообще, чья-то сторонняя библиотеке, которую я могу подгрузить с Гитхаба, или еще откуда. Зачем нужно беспокойство об этом. Да, об этом я читал. _beginthreadex, создает структуру tiddata для CRT, затем вызывает CreateThread. Структура нужна для работы с CRT. Но что нам дает это знание, что все равно вызывается CreateThread? Я почему против CreateThread то, - потому что по словам Рихтера, поток, созданный с ее помощью, не работает с CRT. Вот и вся причина. А так, это единственная функция в Windows, которая способна запустить поток. Нет, так не пойдет. Моя задача докопаться до истины, как бы это не звучало странно. Этот вопрос должен быть закрыт раз и навсегда. Раз я уж взялся за него. Я должен уметь выгружать библиотеку правильно. Для того я и поднял этот вопрос. Обсудить его, прояснить его для себя и нас.
  20. Не понял некоторых твоих слов. По поводу CreateThread, вот выписка с MSDN Remark CreateThread Так что никаких CreateThread. Только _beginthreadex. Более того, даже std::thread использует _beginthreadex. Дальше, по логике, так как поток мы создаем через функцию _beginthreadex,то и выход должен быть через соответствующую ей функцию _endthreadex, которая вызывается неявно когда поток возвращает управление через свой return. Но при вызове FreeLibraryAndExitThread вызывается ExitThread, а не _endthreadex, соответственно блок памяти потока tiddata не освобождается, это первая утечка. Вторая утечка, произойдет если поток не выйдет через свой return, а выйдет раньше, примеры кода я тебе написал выше. Также, DLL не выгрузится, если поток который впоследствии вызовет FreeLibraryAndExitThread, был создан через _beginthreadex. Да это и неправильно, как я уже написал. Я загружаю DLL через свою EXE, через CreateRemoteThread В DLL createThreadGUI() threadProcedure
  21. Разница есть, в утечке памяти. Сравни с этим. Первый код выведет, второй код выведет. Но это мы рассмотрели только объекты нами созданных классов. А помимо них есть еще и другие объекты классов, в библиотеках С++. Да и кто еще знает, что там еще есть, что еще очищается при выходе через естественный return. Так что давай, не разводи полемику, а помоги мне разобраться. Так ли все есть на самом деле, как я описал в этом топике.
  22. Я бы так не сказал. Я привожу цитаты в знак что они не мои, что они из проверенных источников. Я пытаюсь докопаться до истины, всего-то. Не понял этого предложения. Прямой или не прямой вызов ExitThread, - в любом случае, при ExitThread, поток уже не выйдет через return своей процедуры.
  23. Мешает race condition. Ведь - - я вызываю FreeLibrary из потока, reference count для DLL уменьшается, становится 0. Система готова выгрузить DLL, но, вначале идет вызов DllMain - вызвается DllMain с DLL_PROCESS_DETACH. Всё, система решается выгрузить DLL. И выгружает, допустим. Но у нас же там еще поток не завершен, и плюс мы туда еще должны вернуться, из FreeLibrary(). А куда возвращаться, кода DLL уже нет в памяти. Это из MSDN Remak для FreeLibraryAndExitThread А это из книги Рихтера Не зря придумана FreeLibraryAndExitThread. Но, она нам не подходит, как я написал уже. Она вызывает ExitThread, это плохо, по Рихтеру. Плюс она вызывает ExitThread а не _endthreadex. Ведь мы должны запустить поток с _beginthreadex, и завершить его мы должны соответственно с _endthreadex, чтобы очистить в потоке блок памяти tiddata.
  24. Потому что так пишет Рихтер. Как я написал в начале поста, Рихтер настоятельно не рекомендует самостоятельное завершение потока. Далее, по логике Рихтера, так как API функция FreeLibraryAndExitThread, вызывает ExitThread, - значит этот вариант выгрузки DLL отпадает. Тем более этот вариант отпадает, что согласно моему тесту, FreeLibraryAndExitThread, вызванная из потока запущенного через _beginthreadex, не выгружает библиотеку! Даже не вызывается DLL_PROCESS_DETACH. А вот если FreeLibraryAndExitThread вызвана из потока запущенного через CreateThread, тогда библиотека выгружается. Но по совету того же Рихтера, нужно использовать всегда _beginthreadex. Значит, нужно использовать только _beginthreadex и FreeLibrary. Но на MSDN пишут Получается расхождение. Потому что Рихтер так пишет. Поток должен выйти через свой return 0. Если завершить поток в DLL_PROCESS_DETACH, он уже не вернется в свою процедуру, и не вызовет деструкторы и прочие подобные вещи, который компилятор встраивает в конце процедуры. Итог, нужно соблюсти следующие условия. 1 - поток запускается только через _beginthreadex 2 - DLL выгружается только через FreeLibrary 3 - поток завершается только сам, возвращая управление через return 0.
  25. Придумал вариант получше. Никаких дополнительных DLL. Ехе файл инжектора вначале инжектит основную DLL, и записывает в специальную её переменную свой путь на диске. Далее Exe файл завершает свою работу. Затем, когда нужно выгрузить DLL, эта DLL находит по переданному ей пути Exe файл инжектора, и запускает его с параметром Unload. Далее Exe делает все то же что и ранее делала дополнительная DLL. То есть Exe выгружает DLL, а затем и сам завершается. Если DLL не найдет Exe по указанному пути, или если процесс в который была заинжектена DLL будет намерен завершиться, то Exe не будет запускаться.
×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.