@Linda-chan

Тег программизм в блоге Linda-chan

Linda-chan

Не прошло и трёх лет, а у меня, наконец, дошли руки до ActiveX компонентов, вызываемых без регистрации. Оказалось, что сложного там ничего нет, нужно будет автоматизировать генерацию манифестов. Единственное что, в NT4 и Win9x не работает (хотя, в Windows 98 зачатки какие-то были).

Linda-chan

UNIX время – это число с плавающей точкой, в UTC (нулевой часовой пояс), без дополнительных секунд. Всё верно? Запуталась уже =_=

Linda-chan

Ранее я писала, как Win16 выдавала мне страшное сообщение об ошибке при попытке вызвать функцию из не найденной DLL в VB3. Я подумала и нашла источник проблемы. Есть в Windows такая функция SetErrorMode(), которая устанавливает глобально для задачи (процесса в Win32), как будут обрабатываться некоторые ошибки. Например, можно сказать, чтобы при возникновении необработанного исключения программа просто схлопывалась и не выдавала никаких «Память не может быть read». Есть там флаг SEM_NOOPENFILEERRORBOX, который именно на это и отвечает. Если установить его для задачи, то выдача страшных сообщений прекратится, пользователь не будет знать, что программа чего-то не нашла, а программа сама будет действовать альтернативно. Собственно, после установки этого флага, сообщения прекратились. А в Win32 он вроде как установлен по умолчанию (хотя, документация говорит обратное), но, как мне показалось, даже если его сбросить, никаких сообщений не появится.

Linda-chan

There is a horrible non-obvious quirk of the Adjust­Token­Privileges function that is tripping us up: The function returns success even though it may have failed to do what you asked.
The function “succeeded” in the sense that it successfully attempted to adjust the privileges you requested, and it successfully reported the result of the adjustment attempt. But that doesn’t mean that the attempt actually accomplished what you asked it to do.

https://devblogs.microsoft....0211126-00/?p=105973

Linda-chan

В Windows 3.xx, если VB3 программа пытается вызвать функцию из отсутствующей DLL, появляется то самое системно-модальное окно сообщения, поясняющее, что данной библиотеки не найдено. После этого (если не установить обработчик ошибок) уже VB рантайм вываливает ошибку «File not found» и схлопывается. В принципе, это происходит и при запуске такой программы в NT и 9x. А вот в VB6 такой фигни нет.


Linda-chan

У MessageBox() есть ещё один прикольный флаг – MB_SYSTEMMODAL. В Win32 он ничего заметного не делает (документация говорит, что окно сообщения появляется поверх всех окон, что эквивалентно MB_TOPMOST), зато в Win16 показывает окно сообщения, которое блокирует всю систему пока не нажмёшь на кнопку. При этом, если не указать флаг иконки или указать MB_ICONSTOP, то показывается простейшее окно фиксированного размера, без заголовка (текст заголовка пишется отдельной строкой), с текстом шрифтом System и кнопкой. Такое окно рассчитано на ситуации, когда системные ресурсы закончились, система не может даже окно нормально нарисовать, но сообщение показать всё равно нужно, и делается это минимальными средствами. Если же указать другую иконку, то показывается обычное окно сообщения, только с одинарным бордюрчиком и без возможности окно это перетаскивать. Система при этом всё равно блокируется. Ещё одна интересная особенность заключается в том, что в Win9x приложения Win16 могут показывать такое окно с полной блокировкой системы, а Win32 приложения – нет. В NT даже Win16 приложения не могут заблокировать систему.

Linda-chan

В Windows есть функция MessageBox() сотоварищи, которая выводит окно с сообщением, иконкой и набором кнопок для реакции пользователя. Для выбора иконки есть следующие флаги:
• MB_ICONHAND – выводит красную фигню с крестиком, типа, сообщение об ошибке.
• MB_ICONQUESTION – выводит фигню с вопросительным знаком.
• MB_ICONEXCLAMATION – выводит фигню с восклицательным знаком, типа, предупреждение.
• MB_ICONASTERISK – выводит фигню с буквой «i», информация.
В глаза бросается некое несоответствие названия констант тому, что они показывают. Более того, у MB_ICONHAND есть вносящий ясность псевдоним – MB_ICONSTOP. Что такое? Почему так? Дело в том, что названия констант говорят о том, что показывало окно сообщения в самой первой версии Windows. Тогда вместо креста при ошибке показывалась поднятая рука, а вместо буквы «i» – «*». В Windows 3.x руку посчитали неинтересной и стали показывать знак «Движение без остановки запрещено», и у константы появился «псевдоним», отразивший новые реалии. Та же фигня и со звёздочкой: появилась буква «i», и константа начала называться MB_ICONINFORMATION. В Windows 9x и NT4 иконки снова обновили, вместо знака появился крест, и авторы решили перейти от формы к содержанию, добавив псевдонимы MB_ICONERROR и MB_ICONWARNING. Получилась занятная капсула времени.

Linda-chan

Забавная штука, которая встречается в QuickBasic, VBDOS, а так же в VB до третьей версии включительно. Короче, объявляю MessageBox(), потом вызываю её. «Duplicate procedure name». Начинаю разбираться, вдруг она где-то ещё объявлена. Нет, всё в порядке. Перезапускаю IDE – бывало там что что-то не работало без перезапуска – но тоже нет. Замечаю, что это функция, а вызываю я её как процедуру (функцию без возвращаемого значения), ну и добавляю скобочки и Call, как то и дело для наглядности делаю в VB6 и VBScript. Но снова ничего не работает. Догадываюсь, добавляю получение возвращаемого значения, и всё начинает работать. И вот по забывчивости я несколько раз ловила такой прикол в разных, хоть и подобных языках. И каждый раз много думала =_=

Linda-chan

Я чего с сегментами памяти прерываниями DOS заморачивалась? А вот для чего.



Linda-chan

QuickBasic от QBasic помимо наличия компилятора отличается ещё и возможностью запилить проект из нескольких модулей. Как-то раньше не требовалось пилить программы из нескольких модулей на QB ^^'

Linda-chan

В порыве ностальгии научилась на QuickBasic получать PSP программы, а оттуда – блок с переменными окружения. Говорят, что за ним находится имя текущего екзешника, но пока это работает только в DOSBox.

Linda-chan

В программизме самое сложное – рассматривая очень старый, местами неказистый, код, не думать, что человек, который его писал – не очень умный человек, а вот сейчас-то у тебя опыта больше и такую фигню ты больше писать не будешь. Короче, есть такая функция, GetLongPathName(). Думает она то же, что и GetShortPathName(), но в обратную сторону. В Windows 9x и NT4 её не было, и народ там страдал. Функция полезна, например, тем, что позволяет сделать регистр символов в произвольном имени файла как оно на самом деле на диске. Но в Windows 9x её нет, как и в NT4, а описание GetShortPathName() рекомендует использовать FindFirstFile() для нужного нам эффекта. Поскольку эта функция возвращает не прямо полное имя файла, а только имя без пути, нужно пробежаться по всему имени файла и для каждого компонента применить эту функцию. Муторно, но реализуемо, что я и сделала в далёком 2013 году на Цэ. Но вот мне потребовалось то же самое на FreeBasic, и, глядя на тот код, стало грустно. Решила написать заново. Получилось довольно ловко, хитро и гораздо компактнее. И всё заработало! Но потом полезли нюансы, каждый из которых надо было учесть, что влекло увеличение кода и потерю ловкости. Но самое печальное – не было всего этого в коде на Цэ, и из него не лезли все эти нюансы! Короче, пострадала, попечалилась и портировала код на FB, заодно отловив один баг. И вроде не такой уж и неуклюжий код то был, тоже ловкий, просто большая часть непонятного мусора – управление строками. В итоге у меня снова всё работает под Windows 9x и, что немаловажно, на NT4.

Linda-chan

Есть такая функция FindFirstFile(), которой передаём имя файла или путь с масками. В ответ получаем набор найденных файлов, точнее, данные о первом найденном файле и манипулятор, которым можно перечислить остальные элементы набора. Забавное случается, если попытаться передать функции имя каталога с слэшем на конце. Функция прекрасно что-то находит, возвращает манипулятор и данные, только вот в данных – пустота, всё по нулям. Что именно она там находит, я так и не выяснила. GetLastError() возвращает ERROR_FILE_NOT_FOUND, FindNextFile() говорит, что файлов не осталось.

Linda-chan

Есть такие функции как GetOpenFileName() и GetSaveFileName(), которые выводят диалоги открытия и сохранения файла. Они могут показывать диалог в новом стиле и диалог в старом стиле (как в Windows 3.xx). При чём флаг OFN_EXPLORER прямо не влияет на выбор вида диалога, и в обычных ситуациях всегда показывается новый диалог независимо от этого флага. Чтобы показать старый диалог, нужно не только не указать этот флаг, но и подкинуть функции хук, который будет всегда возвращать FALSE (тоесть сигнализировать, что сообщение должна обработать библиотека, а не код хука). Это присказка. Сказка в том, что в Windows 2000 и Windows XP новым был диалог с панелькой неких предопределённых папок слева (которые правились через TweakUI). В Windows Vista диалог переделали, и в левую часть впилили дерево каталогов, а сверху убрали раскрывающийся список с деревом каталогов, впилив вместо него хитрый текстбокс с путём к текущему каталогу. И все нормально написанные программы в новой системе тут же начали показывать новый диалог, если, конечно не использовали хитрые шаблоны. Но я заметила, что были программы, которые выводили диалог, выглядящий как в Windows XP. Экспериментируя, я выяснила, что флаг OFN_EX_NOPLACESBAR, который в предыдущих версиях системы отрубал сайдбар слева и превращал диалог в такой, какой был в Windows 9x или NT4. В Windows Vista и выше оно работает примерно так же, и диалог даже начинает выглядеть примерно так же. Но это всё равно не то. Оказалось, что для того чтобы получить диалог как в XP. нужно провернуть тот же трюк, как со старым диалогом: указываем флаг OFN_EXPLORER и подкидываем такой же хук (что характерно, прототип у старого и нового хука одинаковый, но оба задокументированы отдельно друг от друга). И получаем немного ностальгии.

Linda-chan

Забавное. Есть функция ExpandEnvironmentStrings(), которая берёт строку и разворачивает в ней переменные окружения. Работает она типично: сначала запускаем, передавая NULL вместо приёмного буфера и 0 в качестве длины этого буфера, получаем нужный размер буфера и запускаем второй раз с подготовленным приёмным буфером. Некоторые функции, работающие по этому принципу, NULL не хотят, но там можно просто пустой буфер передать (хоть указатель на int с нуликом). Windows 95 возмутилась и тому, и тому варианту, GetLastError() указывает на ошибку в параметрах, хотя более поздние версии работают нормально. Выяснилось, что нулевой длины буфер функция не принимает, поэтому пришлось первый вызов делать с буфером длиной два символа, и тогда всё заработало, как надо.

Linda-chan

IsDebuggerPresent
Windows NT – Yes
Win95 – No

А в Windows 98 точно добавили. Забавно, что в той справке (которая как раз во времена Windows 95 была выпущена, win32.hlp) import library не указана, а указано в самом тексте:

This function is exported from KERNEL32.DLL.

Linda-chan

Виталик повторяет бегущий гэг про «Почему программисты не могут сразу писать программы без ошибок» IRL!
http://juick.com/m/3002769

Linda-chan

Пока мы ломали копья вокруг FreeBasic и FASM, случилась X Y проблема.

Как оно было? Моя библиотека (которую используют почти все мои программы, написанные на VB6) содержала пару функций для записи сообщений в журнал Windows, так же она содержала ресурс с шаблоном сообщения, который использует системный просмотрщик событий, ну и прописывалась источником этих самых шаблонов (источник событий). В Windows NT4/2000/XP всё работало офигенно: события пишутся, выводятся, замечательно. В x64 Windows 7 выяснилось, что просмотрщик не видит шаблона. Запись в реестре есть, файл есть, шаблонов нет.

«Разные разрядности!» – решила я и даже как-то не подумала посмотреть, что там с другими истониками. Тоесть x64 система почему-то не видит ресурсов в x86 DLL.

Однажды у меня дошли руки до сооружения отдельной DLL с ресурсом для x86 систем и отдельной – для x64 систем. Тоесть при установке программы копируем нужный файлик, и система его радостно использует. Исходную библиотеку я пишу на FreeBasic (предыдущая версия была вообще на VC++ 6), ну и эти ресурсные я решила запилить на FreeBasic.

Тут же появилось две проблемы. Во-первых тяжёлый фрибишный рантайм, впиливающийся в код библиотеки (у VB рантайм, например, хранится в легендарном MSVBVM60.DLL). Оказалось, что чтобы его искоренить, нужно всю компиляцию делать руками и городить костыли. А во-вторых, компиляторы, поставляемые с FreeBasic работают по принципу «Делаю бинарник только своей разрядности». Тоесть x86 бинарник делается x86 версией компилятора, x64 – x64 версией компилятора, а под линупс (if any) вообще под линупсом надо собирать. А я на XP :}

И тут вспомнился, собственно, FASM, который по своей природе не содержит рантаймов (ассемблер же) и собирает где угодно какой угодно бинарник (ассемблер же). Им я и сделала нормальные ресурные DLL.

А потом я задумалась, как их устанавливать. В реестре, в записи источника событий не указывается отдельно разрядность. Но что если просмотрщик будет не той же разрядности, что и система? Начала экспериментировать на x64 системе.

И тут я сделала два важных открытия. Во-первых, источник событий для моих программ прописывался без пути, просто именем файла. А во-вторых, он лежал в SysWOW64, поскольку x86. Иными словами, просмотрщик не то что не мог загрузить ресурс, он тупо не находил файл там, где ожидал его увидеть – в System32. Когда я прописала абсолютный путь, все события сразу же начали показываться нормально и с x86 DLL. А когда я посмотрела, как событие VB6 рантайма прописано по соседству, то нашла там запись в духе «C:\Windows\SysWOW64\msvbvm60.dll».

Всё это время я решала не ту задачу. Настоящим решением должно стать прописывание полного пути к DLL для новой библиотеки (при установке программы, которая её использует) и создание симлинка в System32 для старой (там код я поправить уже не могу).

Linda-chan

This function dates back to Windows 3.1, back when a powerful computer had 4MB of memory, and your typical computer had much less. Software development kits cost thousands of dollars, and the expectation was that if you bought one, it was because you were a professional developer who understood how the system worked down to a very low level. Programming was hard because nobody expected it to be easy.

https://devblogs.microsoft....0210928-00/?p=105737

Linda-chan

Одна из приятных особенностей использования FASM заключается в том, что чтобы сделать x64 бинарник, не нужно запускать x64 компилятор на x64 системе. Достаточно указать в исходнике, что это будет за бинарник, и нужный код будет сделан даже на x86 системе.

Добавить пост

Вы можете выбрать до 10 файлов общим размером не более 10 МБ.
Для форматирования текста используется Markdown.