Всем привет, в этой статье в хочу поведать, какие трудности могут ожидать неопытного человека, который соблазнится нативным программированием.
Оставь надежду, всяк сюда входящий. Или... нет?
Имея небольшой опыт в веб-программировании, мне казалось, что все не так плохо. И так по началу и было. За вопрос я взялся основательно: без задачи — нет учебы.
Я решил поставить перед собой большую цель: давным-давно, играя в ммо, я наткнулся на бот-программу, так называемый пакетный кликер. Она отправляла запросы на сервер и заставляла персонажа выполнять в автоматическом режиме невообразимые вещи, что меня очень впечатлило. По заявлениям автора, он ее сделал всего за 3 часа. И вот, уже не маленький я решил, что должен сделать так же.
Бот я выбрал по ряду причин:
Работа с ассемблером.
Какой-никакой GUI.
Сборка и импорт библиотеки.
Мечта детства.
Начал я с реверсинга, попал на форум Tuts4You и прошел челлендж от lena151 (и ее 2006й), состоящий из 40ка reverse_me.
![Пример из челленджа от lena151 (2006) Пример из челленджа от lena151 (2006)](https://habrastorage.org/getpro/habr/upload_files/740/843/262/740843262ed211121ede3eab0cfe4b5b.png)
Закрепил навыки на коммерческом продукте, запакованном при помощи VMProtect
![Успешно пойденная регистрация в программе Успешно пойденная регистрация в программе](https://habrastorage.org/getpro/habr/upload_files/c1a/1aa/40b/c1a1aa40b5dde1ab3c000953a8f339bc.gif)
Приступил к созданию библиотеки и импорту ее в игру, отправка пакета прошла успешно.
![отправка пакета через вешнюю библиотеку, призыв питомца :з отправка пакета через вешнюю библиотеку, призыв питомца :з](https://habrastorage.org/getpro/habr/upload_files/62e/8ff/f38/62e8fff38acf25ae5c573ded0004ddb1.gif)
Потеряв голову от “успеха”, я решил, ну все.. Я готов явить себя миру!
Кроссплатформенное GUIовое приложение
Первым препятствием стал выбранный мной язык - Си. Писать на нем что-то большое - очень больно. Но я сдался не сразу и даже сделал на WinAPI… скролл…
![C language WINAPI оконное приложение со скроллбаром :c C language WINAPI оконное приложение со скроллбаром :c](https://habrastorage.org/getpro/habr/upload_files/a82/e59/dc9/a82e59dc9ee361773e74ef7a0cb19493.gif)
Мы плавно подошли к самому главному…
![Сняли с языка : ) Сняли с языка : )](https://habrastorage.org/getpro/habr/upload_files/f68/a06/c12/f68a06c127a2e72422a035c2ef2871a7.jpg)
GUI обыкновенный или я твой Antialiasing шатал
Так как все это для обучения и только для обучения. Я решил, делать, так делать. Чтобы один и тот же код работал одинаково плохо хорошо на разных платформах.
Под рукой у мня был старенький мак с MacOS Catalina и ПиСюк с Windows 10. Исследовав рынок фреймворков я нашел 2 кандидата Qt и wxWidgets, но, поскольку Qt это про деньги и вообще попса.. А все крутые ребята идут в андеграунд, выбор пал на wxWidgets.
В двух словах о wxWidgets - это нативный Фреймворк, который дает низкоуровневый доступ к системе. То есть я могу сам решить, какими средствами отрисовывать, как хранить и выводить результат.
Например, под виндой мы можем взять Direct2D или GDI, причем использовать все, что доступно одновременно, рисуя в Bitmap по очереди, используя разные средства, а после вывести ее.
При большой настойчивости можно даже подкрутить OpenGL. Но это уже другая история….
![Думал, что можно все! Думал, что можно все!](https://habrastorage.org/getpro/habr/upload_files/8c3/f4b/b40/8c3f4bb407c250e97524bee003fe6f43.gif)
От удивления чуть не слетели штаны, придерживая их одной рукой, второй я тут же скачал бесплатное кросcплатформенное приложение Lunacy и начал наворачивать крутой интерфейс, скругленые углы, трансперенси, блюр… У нас будет их все!
![макет приложения в lunacy макет приложения в lunacy](https://habrastorage.org/getpro/habr/upload_files/d17/ca2/22d/d17ca222d749eba6aa486209c975e5fd.jpg)
Но в итоге, все пошло не по плану.
При работе с unixом, мак или линукс, практически все работает из коробки, но Windows разочаровывает и заставляет разделить свой седалищный нерв на ДО и ПОСЛЕ.
![Try HARD.. Try HARD..](https://habrastorage.org/getpro/habr/upload_files/fbb/cdd/f28/fbbcddf281d6f3480572cef7037a6de0.gif)
Начиная с конфликта пользовательской отрисовки с системной, когда я рисую свое, а параллельно система… Ну, почему бы и нет. Пришлось отказаться от обработки OnPaint события для каждого элемента и делать все в основном, пробрасывая указатели на функцию отрисовки для каждого элемента и выводить в окно Bitmap по готовности, благодаря этому система не имеет доступа к нашему буферу.
![Пример системной отрисовки параллельно пользовательской.. Пример системной отрисовки параллельно пользовательской..](https://habrastorage.org/getpro/habr/upload_files/3b1/3ea/157/3b13ea1573bf9447f9c41978a6b78124.gif)
Но результатом всех этих мучений стало то, что всю грязную работу при работе с контролями (размеры, позиция, события) берет на себя система, а мы просто берем и рисуем свои крутости в окно.
И здесь я бы хотел продемонстрировать микро-гайд, как создать простое окно без рамки и накидать в него наши ништяки кастомные контролы, надеюсь, это даст Вам пищу для размышлений при создании своих проектов. Уточню, что я не заканчивал техно-ВУЗов, не являюсь техно-гуру и иже с ними. Я просто неравнодушный скиталец, потому, прошу простить за неточности и ошибки.
* Библиотека
Если Вы работаете под Windows, то Вашим выбором наверняка должен стать MinGW, потому, что они проделали большую работу, по приведению вин среды к GNU подобной.
Все отлично собирается при помощи gccшного компилятора и готовые библиотеки wxWidgets доступны в репозитории pacman.
win_x86
pacman -S mingw-w64-i686-wxwidgets3.1-msw
pacman -S mingw-w64-i686-wxwidgets3.1-msw-libs
win_x64
pacman -S mingw-w64-x86_64-wxwidgets3.1-msw
pacman -S mingw-w64-x86_64-wxwidgets3.1-msw-libs
Под MacOS мне пришлось собирать все самому, собирая из библиотек доступных в репозитории macports я не смог нормально залинковаться, но может это моя криворукость.
git clone https://github.com/wxWidgets/wxWidgets
cd wxWidgets
mkdir build-cocoa-debug
cd build-cocoa-debug
../configure --enable-debug
make
Собираем семплы и демки
cd samples; make;cd ..
cd demos; make;cd ..
* Makefile
Далее создадим make file.
Единственным отличием Windows от MacOS является сборка ресурсов (картинок, иконок и др.)
Под Windows мы используем windres, чтобы захардкодить их в объектный файл, в данном случае я назвал его resource.o
![Пример Make файла под Windows Пример Make файла под Windows](https://habrastorage.org/getpro/habr/upload_files/784/a4a/f24/784a4af249b425f1296c0ee3f289f55a.png)
Под MacOS мы просто собираем bundle и кладем их в папочку, без разбора копируем все из папки ./src
![Пример Make файла под MacOS Пример Make файла под MacOS](https://habrastorage.org/getpro/habr/upload_files/0ce/a99/63e/0cea9963e7d03f53926c3b8d16be89db.png)
* Main.cpp
Создаем MAIN.CPP
![Пример файла main.cpp Пример файла main.cpp](https://habrastorage.org/getpro/habr/upload_files/62c/531/034/62c531034879c6e039add1eb7c0f8a73.png)
![Пример файла surface.h Пример файла surface.h](https://habrastorage.org/getpro/habr/upload_files/c51/f7e/d09/c51f7ed09a9a6c8c3db157647ee3ec3e.png)
Получаем простое-пустое окно
![Результат работы нашего кода - пустое окно без оконной рамки.. Результат работы нашего кода - пустое окно без оконной рамки..](https://habrastorage.org/getpro/habr/upload_files/acd/8c9/258/acd8c9258c59ca139b2681123cdd0f8c.gif)
Добавление ресурсов (вин/мак), происходит удивительно легко, как я уже упомянул, в Windows мы все собираем в объектный файл, а под MacOS просто собираем bundle, после можно простым вызовом макроса wxBitmap bmpName("bmp_name_without_png_ext", wxBITMAP_TYPE_PNG_RESOURCE);
получуть переменную bmpName, в которой будет наша картинка.
![Не забудьте создать под Windows файл resource.rc, прописать путь и типы переменных. Не забудьте создать под Windows файл resource.rc, прописать путь и типы переменных.](https://habrastorage.org/getpro/habr/upload_files/873/96a/044/87396a0440dab5c5cfc7e56c1c5ac9f8.png)
Отрисовка с проброской указателя на функции. Чтобы избежать проблем с мерцанием, полосованием и прочей нечестью, мы не обрабатываем каждый элемент по отдельности. Получим событие OnPaint(wxPaintEvent& e)
мы вызываем из нашего списка дочерние методы по указателю.
Bindимся к нашему методу в конструкторе Bind(wxEVT_PAINT, &Surface::OnPaint, this);
![Пример обработки события Paint Пример обработки события Paint](https://habrastorage.org/getpro/habr/upload_files/690/781/08f/69078108ff7d170e4c1cfcf342c22b99.png)
![Мой чудо-каст методов для отрисовки отдельных элементов : ) Мой чудо-каст методов для отрисовки отдельных элементов : )](https://habrastorage.org/getpro/habr/upload_files/8e7/a96/bb5/8e7a96bb53d3f455df4892f47859db2b.png)
После всех мучений я остановился на этом
![Накашлял : ) Накашлял : )](https://habrastorage.org/getpro/habr/upload_files/1ba/f77/ce1/1baf77ce126b3bdb2322073df02b44d7.gif)
ПЫ. СЫ. Все действия производятся исключительно в образовательных целях и не являются призывом к действию.
Комментарии (8)
voldemar_d
05.11.2023 10:04+4Можете сформулировать, каков итог проделанных действий?
Что удалось получить в результате? Кросс-платформенное приложение, которое что-то в окошке рисует? По картинкам не очень понятно.
deamondz
05.11.2023 10:04+3возможно, я не очень понял историю про нативность, но может flutter подойдёт лучше для ваших задач?
me21
05.11.2023 10:04Почему бы не взять Qt?
voldemar_d
05.11.2023 10:04Тот же вопрос. Почему автор пишет "поскольку Qt это про деньги и вообще попса..."?
О каких деньгах речь, и почему попса? А то люди пишут на Qt и не знают.
svn74
05.11.2023 10:04Очередной велосипед... Хотите писать кроссплатформенные приложения - берите Java,- это лучшее , что было придумано для кросс...
vassabi
да, нативное рисование - это точно что "нарисовать пиксель" - все просто, "нарисовать скролл с табами" - !!**%*%**!!
помнится, когда работал в контроле игроделов, то в какой-то момент весь "нативный UI" перерисовали в 3Д, потому что "создал контекст, передал текстуры" - дальше игровой движ.работает везде одинаково.