Как создать com файл
Перейти к содержимому

Как создать com файл

Пошаговое руководство. Создание объектов COM с помощью Visual Basic

при создании новых приложений или компонентов лучше создавать сборки платформа .NET Framework. однако Visual Basic также упрощает предоставление платформа .NET Framework компонента COM. Это позволяет предоставлять новые компоненты для более ранних версий приложений, требующих COM-компонентов. в этом пошаговом руководстве показано, как использовать Visual Basic для предоставления объектов платформа .NET Framework в виде com-объектов как с шаблоном com-класса, так и без него.

Самый простой способ предоставить COM-объекты — использовать шаблон COM-класса. Этот шаблон создает новый класс, затем настраивает проект для создания класса с уровнем взаимодействия в качестве COM-объекта и зарегистрируйте его в операционной системе.

хотя можно также предоставить класс, созданный в Visual Basic, как COM-объект для использования неуправляемым кодом, он не является настоящим com-объектом и не может использоваться Visual Basic. дополнительные сведения см. в разделе COM-взаимодействие в платформа .NET Framework приложениях.

Отображаемые на компьютере имена или расположения некоторых элементов пользовательского интерфейса Visual Studio могут отличаться от указанных в следующих инструкциях. Это зависит от имеющегося выпуска Visual Studio и используемых параметров. Дополнительные сведения см. в разделе Персонализация среды IDE.

Создание COM-объекта с помощью шаблона класса COM

откройте новый проект Windows приложения в меню файл , щелкнув создать Project.

убедитесь, что в диалоговом окне новый Project в поле типы Project выбрано значение Windows. В списке шаблоны выберите пункт Библиотека классов , а затем нажмите кнопку ОК. Отобразится новый проект.

выберите добавить новый элемент в меню Project . Откроется диалоговое окно Добавление нового элемента.

Выберите класс COM в списке шаблоны и нажмите кнопку добавить. Visual Basic добавляет новый класс и настраивает новый проект для COM-взаимодействия.

Добавьте в класс COM код, например свойства, методы и события.

Выберите Сборка ClassLibrary1 в меню Сборка . Visual Basic создает сборку и регистрирует COM-объект в операционной системе.

Создание COM-объектов без шаблона класса COM

Можно также создать COM-класс вручную вместо использования шаблона COM-класса. Эта процедура полезна при работе из командной строки или в том случае, если требуется больший контроль над определением объектов COM.

Настройка проекта для создания COM-объекта

откройте новый проект Windows приложения в меню файл , щелкнув NewProject.

убедитесь, что в диалоговом окне новый Project в поле типы Project выбрано значение Windows. В списке шаблоны выберите пункт Библиотека классов , а затем нажмите кнопку ОК. Отобразится новый проект.

В обозревателе решений щелкните правой кнопкой мыши на проект и выберите пункт Свойства. откроется конструктор Project .

Откройте вкладку Компиляция.

Установите флажок Регистрация для COM-взаимодействия .

Настройка кода в классе для создания COM-объекта

В Обозреватель решенийдважды щелкните Class1. vb , чтобы отобразить его код.

Переименуйте класс в ComClass1 .

Добавьте следующие константы в ComClass1 . Они будут хранить константы глобального уникального идентификатора (GUID), которые должны иметь объекты COM.

В меню Сервис выберите пункт Создать GUID. В диалоговом окне Создание GUID нажмите кнопку Формат реестра, а затем Копировать. Щелкните Выход.

Замените пустую строку в ClassId идентификаторе GUID, удалив начальные и конечные фигурные скобки. Например, если идентификатор GUID, предоставленный Guidgen, будет "<2C8B0AEE-02C9-486e-B809-C780A11530FE>" выглядеть следующим образом.

Повторите предыдущие шаги для InterfaceId констант и EventsId , как показано в следующем примере.

Убедитесь, что идентификаторы GUID являются новыми и уникальными. в противном случае COM-компонент может конфликтовать с другими COM-компонентами.

ComClass Добавьте атрибут в ComClass1 , указав идентификаторы GUID для идентификатора класса, идентификатора интерфейса и идентификатора события, как показано в следующем примере:

Классы COM должны иметь конструктор без параметров Public Sub New() , иначе класс не будет зарегистрирован правильно. Добавьте в класс конструктор без параметров:

Добавьте свойства, методы и события в класс, завершая его End Class оператором. В меню Сборка выберите пункт построить решение . Visual Basic создает сборку и регистрирует COM-объект в операционной системе.

объекты com, созданные с помощью Visual Basic, не могут использоваться другими приложениями Visual Basic, поскольку они не являются настоящими com-объектами. Попытка добавить ссылки на такие COM-объекты вызовет ошибку. дополнительные сведения см. в разделе COM-взаимодействие в приложениях платформа .NET Framework.

Как собрать досовский COM-файл компилятором GCC

В минувшие выходные я участвовал в Ludum Dare #31. Но даже до объявления тем конференции из-за своего недавнего увлечения я хотел сделать олдскульную игру под DOS. Целевой платформой выбрана DOSBox. Это самый практичный способ запуска DOS-приложений несмотря на то, что все современные процессоры x86 полностью обратно совместимы со старыми, вплоть до 16-битного 8086.

Я успешно создал и показал на конференции игру DOS Defender. Программа работает в реальном режиме 32-битного 80386. Все ресурсы встроены в исполняемый COM-файл, никаких внешних зависимостей, так что игра целиком упакована в бинарник 10 килобайт.

Для игры понадобится джойстик или геймпад. Я включил поддержку мыши в релиз для Ludum Dare ради презентации, но потом удалил её, потому что она не очень хорошо работала.

Наиболее технически интересная часть заключается в том, что для создания игры не понадобились никакие инструменты разработки DOS! Я использовал только обычный компилятор Linux C (gcc). В реальности даже нельзя собрать DOS Defender под DOS. Я рассматриваю DOS только как встроенную платформу, что и есть единственная форма, в которой DOS всё ещё существует сегодня. Вместе с DOSBox и DOSEMU это довольно удобный набор инструментов.

Если вас интересует только практическая часть разработки, перейдите к разделу «Обманываем GCC», где мы напишем DOS COM программу “Hello, World” с GCC Linux.

Поиск правильных инструментов

Когда я начал этот проект, то не думал о GCC. В реальности я пошёл по этому пути, когда обнаружил пакет bcc (Bruce’s C Compiler) для Debian, который собирает 16-битные бинарники для 8086. Его держат для компиляции загрузчиков x86 и прочего, но bcc также можно использовать для компиляции DOS COM файлов. Это меня заинтересовало.

Для справки: 16-битный микропроцессор Intel 8086 вышел в 1978 году. У него не было никаких причудливых функций современных процессоров: ни защиты памяти, ни инструкций с плавающей запятой и только 1 МБ адресуемой RAM. Все современные десктопы и ноутбуки x86 всё ещё могут притвориться этим 16-битным процессором 8086 сорокалетней давности, с такой же ограниченной адресацией и всё такое. Это нехилая обратная совместимость. Такая функция называется реальным режимом. Это режим, в котором загружаются все компьютеры x86. Современные ОС сразу переключаются в защищённый режим с виртуальной адресацией и безопасной многозадачностью. DOS так не поступал.

К сожалению, bcc — не компилятор ANSI C. Он поддерживает подмножество K&R C, а также встроенный ассемблерный код x86. В отличие от других компиляторов 8086 C, у него нет понятия «дальних» или «длинных» указателей, поэтому для доступа к другим сегментам памяти (VGA, тактовые импульсы и т. д.) необходим встроенный ассемблерный код. Примечание: остатки этих «длинных указателей» 8086 до сих сохранились в Win32 API: LPSTR , LPWORD , LPDWORD и др. Тот встроенный ассемблер даже близко не сравнится со встроенным ассемблером GCC. На ассемблере нужно вручную загружать переменные из стека, а поскольку bcc поддерживает два разных соглашения о вызовах, то переменные в коде следует жёстко закодировать в соответствии с одним или другим соглашением.

Учитывая такие ограничения, я решил искать альтернативы.

DJGPP

DJGPP — порт GCC под DOS. Реально очень впечатляющий проект, который переносит под DOS почти весь POSIX. Многие портированные под DOS программы сделаны на DJGPP. Но он создаёт только 32-битные программы для защищённого режима. Если в защищённом режиме нужно работать с аппаратным обеспечением (например, VGA), то программа делает запросы к сервису интерфейса защищённого режима DOS (DPMI). Если бы я взял DJGPP, то не смог бы ограничиться единственным автономным бинарником, потому что пришлось бы поиметь и сервер DPMI. Производительность тоже страдает от запросов к DPMI.

Получить необходимые инструментальные средства для DJGPP сложно, мягко говоря. К счастью, я нашел полезный проект build-djgpp, который всё запускает, по крайней мере, на Linux.

Либо там серьёзная ошибка, либо официальные бинарники DJGPP опять заразились вирусом, но при при запуске моих программ в DOSBox постоянно возникала ошибка “Not COFF: check for viruses”. Для дополнительной проверки, что вирусы не на моей собственной машине, я настроил среду для DJGPP на своём Raspberry Pi, который действует как чистая комната. Это устройство на базе ARM невозможно заразить вирусом x86. И всё равно возникала та же проблема, и все двоичные хэши совпадали между машинами, так что это не моя вина.

Так что учитывая это и проблему DPMI, я начал искать дальше.

Обманываем GCC

На чём я в итоге остановился — так это на хитром трюке по «обману» GCC для сборки DOS COM-файлов реального режима. Трюк работает до 80386 (что обычно и нужно). Процессор 80386 выпущен в 1985 году и стал первым 32-битным x86 микропроцессором. GCC по-прежнему придерживается этого набора инструкций, даже в среде x86-64. К сожалению, GCC никак не может производить 16-битный код, так что от изначальной цели сделать игру для 8086 пришлось отказаться. Впрочем, это не имеет значения, потому что целевая платформа DOSBox по сути является эмулятором 80386.

В теории трюк должен работать и в компиляторе MinGW, но там есть давняя ошибка, которая мешает ему работать правильно (“cannot perform PE operations on non PE output file”). Впрочем, её можно обойти, и я делал это сам: следует удалить директиву OUTPUT_FORMAT и добавить дополнительный шаг objcopy ( objcopy -O binary ).

Hello World в DOS

Для демонстрации создадим досовскую COM-программу “Hello, World” с помощью GCC на Linux.

В этом способе есть главное и значительное препятствие: стандартной библиотеки не будет. Это как писать операционную систему с нуля, за исключением нескольких служб, которые обеспечивает DOS. Это значит, нет printf() и тому подобного. Вместо этого мы попросим DOS вывести строку в консоль. Создать запрос к DOS требует запуска прерывания, что означает встроенный ассемблерный код!

В DOS девять прерываний: 0x20, 0x21, 0x22, 0x23, 0x24, 0х25, 0x26, 0x27, 0x2F. Самое главное, которое нас интересует, это 0x21, функция 0x09 (вывести строку). Между DOS и BIOS есть тысячи функций, названных по такому шаблону. Я не собираюсь пытаться объяснить ассемблер x86, но вкратце номер функции забивается в регистр ah — и прерывание 0x21 срабатывает. Функция 0x09 также принимает аргумент — указатель на строку для печати, который передается в регистрах dx и ds .

Вот функция print() встроенного ассемблера GCC. Строки, передаваемые этой функции, должны заканчиваться символом $. Почему? Потому что DOS.

Код объявлен volatile , поскольку у него побочный эффект (печать строки). Для GCC ассемблерный код непрозрачен, и оптимизатор полагается на ограничения выхода/входа/клоббера (последние три строки). Для таких DOS-программ любой встроенный ассемблер будет с побочными эффектами. Это потому что он пишется не для оптимизации, а для доступа к аппаратным ресурсам и DOS — вещей, недоступных простому C.

Нужно также позаботиться о вызывающем операторе, потому что GCC не знает, что память, на которую указывает string , когда-либо читалась. Вероятно, массив, который поддерживает строку, тоже придётся объявить volatile . Всё это предвещает неизбежное: любые действия в такой среде превращаются в бесконечную борьбу с оптимизатором. Не все из этих битв можно выиграть.

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

COM-файлы ограничены размером 65279 байт. Это связано с тем, что сегмент памяти x86 составляет 64 КБ, а DOS просто загружает COM-файлы в адрес 0x0100 сегмента и выполняет. Заголовков нет, только чистый бинарник. Поскольку программа COM в принципе не может иметь значительный размер, то не должно происходить и никакой реальной компоновки (freestanding), вся вещь компилируется как одна единица трансляции. Это будет один вызов GCC с кучей параметров.

Параметры компилятора

Вот основные параметры компилятора.

-std=gnu99 -Os -nostdlib -m32 -march=i386 -ffreestanding

Поскольку стандартные библиотеки не используются, то единственное различие между gnu99 и c99 заключается в отключенных триграфах (как и должно быть), и встроенный ассемблер можно записать как asm вместо __asm__ . Это не бином Ньютона. Проект будет настолько тесно связан с GCC, что я всё равно не озабочен расширениями GCC.

Параметр -Os насколько возможно уменьшает результат компиляции. Так и программа будет работать быстрее. Это важно с прицелом на DOSBox, потому что эмулятор по умолчанию работает медленно как машина 80-х. Я хочу вписаться в это ограничение. Если оптимизатор вызывает проблемы, то временно поставим -O0 , чтобы определить, тут ваша ошибка или оптимизатора.

Как видите, оптимизатор не понимает, что программа будет работать в реальном режиме с соответствующими ограничениями адресации. Он выполняет всевозможные невалидные оптимизации, которые ломают ваши совершенно валидные программы. Это не баг GCC, ведь мы сами тут делаем сумасшедшие вещи. Мне пришлось несколько раз переделывать код, чтобы помешать оптимизатору сломать программу. Например, пришлось избегать возврата сложных структур из функций, потому что они иногда заполнялись мусором. Настоящая опасность в том, что будущая версия GCC станет ещё умнее и будет ломать ещё больше кода. Здесь ваш друг volatile .

Следующий параметр -nostdlib , поскольку мы не сможем залинковаться ни с какими валидными библиотеками, даже статически.

Параметры -m32-march=i386 командуют компилятору выдавать код 80386. Если бы я писал загрузчик для современного компьютера, то прицел на 80686 тоже был бы нормальный, но DOSBox — это 80386.

Аргумент -ffreestanding требует, чтобы GCC не выдавал код, который обращается к функциям хелпера встроенной стандартной библиотеки. Иногда он вместо реально рабочего кода выдаёт код для вызова встроенной функции, особенно с математическими операторами. У меня это была одна из основных проблем с bcc, где такое поведение невозможно отключить. Такой параметр чаще всего используется при написании загрузчиков и ядер ОС. А теперь и досовских COM-файлов.

Параметры компоновщика

Параметр -Wl используется для передачи аргументов компоновщику ( ld ). Нам это нужно, поскольку мы всё делаем за один вызов GCC.

—nmagic отключает выравнивание страниц разделов. Во-первых, нам оно не требуется. Во-вторых, оно впустую отнимает драгоценное пространство. В моих тестах это не кажется необходимой мерой, но я на всякий случай оставляю эту опцию.

Параметр —script указывает, что мы хотим использовать особый скрипт компоновщика. Это позволяет точно разместить разделы ( text , data , bss , rodata ) нашей программы. Вот скрипт com.ld .

OUTPUT_FORMAT(binary) говорит не помещать это в файл ELF (или PE и т. д.). Компоновщик должен просто сбросить чистый код. COM-файл — это просто чистый код, то есть мы даём команду компоновщику создать файл COM!

Я говорил, что COM-файлы загружаются в адрес 0x0100 . Четвёртая строка смещает туда бинарник. Первый байт COM-файла по-прежнему остаётся первым байтом кода, но будет запускаться с этого смещения в памяти.

Далее следуют все разделы: text (программа), data (статичные данные), bss (данные с нулевой инициализацией), rodata (строки). Наконец, я отмечаю конец двоичного файла символом _heap . Это пригодится позже при написании sbrk() , когда мы закончим с “Hello, World”. Я указал выровнять _heap по 4 байтам.

Запуск программы

Компоновщик обычно знает нашу точку входа ( main ) и настраивает её для нас. Но поскольку мы запросили «двоичную» выдачу, то придётся разбираться самим. Если первой запустится функция print() , то выполнение программы начнётся с неё, что неправильно. Программе нужен небольшой заголовок для начала работы.

В скрипте компоновщика для таких вещей есть опция STARTUP , но мы для простоты внедрим её прямо в программу. Обычно подобные штуки называются crt0.o или Boot.o , на случай, если вы где-то на них наткнётесь. Наш код обязан начинаться с этого встроенного ассемблера, перед любыми включениями и тому подобным. DOS сделает за нас бóльшую часть установки, нам просто нужно перейти к точке входа.

.code16gcc сообщает ассемблеру, что мы собираемся работать в реальном режиме, так что он сделает правильную настройку. Несмотря на название, это не выдаст 16-битный код! Сначала вызывается функция dosmain , которую мы написали ранее. Затем он сообщает DOS с помощью функции 0x4C («закончить с кодом возврата»), что мы закончили, передавая код выхода в 1-байтовый регистр al (уже установленный функцией dosmain ). Этот встроенный ассемблер автоматически volatile , потому что не имеет входов и выходов.

Всё вместе

Вот вся программа на C.

Не буду повторять com.ld . Вот вызов GCC.

И его тестирование в DOSBox:

Тут если вы хотите красивой графики, то вопрос всего лишь в вызове прерывания и записи в память VGA. Если хотите звука, используйте прерывание PC Speaker. Я ещё не разобрался, как вызвать Sound Blaster. Именно с этого момента вырос DOS Defender.

Выделение памяти

Чтобы покрыть ещё одну тему, помните тот _heap ? Можем использовать его для реализации sbrk() и динамического выделения памяти в основном разделе программы. Это реальный режим и нет виртуальной памяти, поэтому можем писать в любую память, к которой мы можем обратиться в любой момент. Некоторые участки зарезервированы (например, нижняя и верхняя память) для оборудования. Так что реальной нужды в использовании sbrk() нет, но интересно попробовать.

Как обычно на x86, ваша программа и разделы находятся в нижней памяти (0x0100 в данном случае), а стек — в верхней (в нашем случае в районе 0xffff). В Unix-подобных системах память, возвращаемая malloc() , поступает из двух мест: sbrk() и mmap() . Что делает sbrk() , так это выделяет память чуть выше сегментов программы/данных, приращивая её «вверх» навстречу стеку. Каждый вызов sbrk() будет увеличивать это пространство (или оставлять его точно таким же). Данная память будет управляться malloc() и подобными.

Вот как можно реализовать sbrk() в программе COM. Обратите внимание, что нужно определить собственный size_t , потому что у нас нет стандартной библиотеки.

Он просто устанавливает указатель на _heap и увеличивает его по мере необходимости. Немного более умный sbrk() также будет осторожен с выравниванием.

В процессе создания DOS Defender произошла интересная вещь. Я (неправильно) посчитал, что память от моего sbrk() обнулилась. Так было после первой игры. Однако DOS не обнуляет эту память между программами. Когда я снова запустил игру, она продолжилась точно там, где остановилась, потому что те же структуры данных с тем же содержимым были загружены на свои места. Довольно прикольное совпадение! Это часть того, что делает забавной эту встроенную платформу.

Тема: Создание com/exe файла

Начал изучать Ассемблер . В учебнике прочитал небольшую иструкцию :

Допустим, вы создали в текстовом редакторе файл с именем PROG.ASM.
Если вы используете MASM 6.11—6.13, в командной строке необходимо указать следующее:
> ML.EXE PROG.ASM /AT
В результате будут созданы два файла: PROG.OBJ и PROG.COM. Файл PROG.OBJ, скорее всего, вам больше не понадобится, и его можно удалить, а PROG.COM можно запускать на выполнение. Это и будет машинный код ассемблерной программы. Параметр /AT указывает программе-ассемблеру (MASM), что после ассемблирования, в случае, если ошибок не будет обнаружено, следует запустить компоновщик (LINK.EXE) и передать ему параметры для создания файла типа COM.

Программу в формате asm создал , а что делать дальше ? Обьясните пожалуйста в какую именно командную строку это надо ввести , или как запустить MASM , в общем как создать exe/com файл ??

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *