Софт-Портал

Icalc

Рейтинг: 5.0/5.0 (1195 проголосовавших)

Категория: Windows: Калькуляторы

Описание

The Calc - скачать бесплатно The Calc

The Calc 3.02

The Calc - многофункциональный калькулятор, конвертер физических единиц, калькулятор дат и конвертер календарей, универсальный решатель алгебраических уравнений.

The Calc вычисляют арифметические операции и операции со скобками, тригонометрические функции, натуральные, двоичные, десятичные и произвольные логарифмы, степенные и экспоненциальные функции, модуль, факториал. Как выражение, так и результат могут быть представлены в любой системе исчисления от двоичной до шестнадцатеричной, причем, в отличие от большинства других калькуляторов, в не десятичных системах исчисления могут быть записаны не только целые, но и дробные числа. Тригонометрические выражения могут быть посчитаны в градусах или в радианах, причем и числа в градусах и числа в радианах могут произвольно смешиваться в одном выражении. Также возможна работа не только с десятичными, но и с натуральными дробями.

Возможна работа, как мышью, так и с клавиатуры, причем при работе с клавиатуры допустимо использовать только русскую раскладку. Имеется неограниченное количество удобно управляемых ячеек памяти, неограниченное количество, подключаемых "на лету" пользовательских функций и констант, точность от 0 до 16 десятичных знаков.

Встроенный модуль пересчета единиц измерения содержит более 650 единиц измерения разбитых на 21 категорию, что ставит его на уровень самых продвинутых программ такого рода. Модуль работы с датой может не только складывать и вычитать даты и периоды и рассчитывать день недели любой даты, но и может конвертировать дату между основными ныне действующими календарями – Григорианским, Юлианским, Мусульманским (лунной хиджры), Еврейским.

Модуль решения уравнений позволяет решать любые алгебраические уравнения вида f(x)=0. например 2*x^2-20x+10=0 или SQRT(5*x^12)-(cos(x^3))^3+ln(x)=0.

В бухгалтерском режиме калькулятор осуществляет операции с процентами прибавляет/вычитает/выделяет 10% и 18% НДС, ведет расчет основных Российских налогов. Может копировать результат текстом. Вычисляет 18 финансовых функций(аннуитет, амортизация и др.)

В химическом режиме представлена таблица Менделеева (может быть изображена в нескольких различных видах) и множество данных по каждому элементу. Возможно вычисление молекулярной массы вещества, процентного состава элементов в веществе, уравнивание сложных химических реакций, причем в отличие от многих других программ такого рода, где сложные реакции могут уравниваться десятки минут, TheCalc обычно уравнивает реакции за доли секунды.

Скриншоты The Calc :

Icalc:

  • скачать
  • скачать
  • Другие статьи, обзоры программ, новости

    Calc - это

    Смотреть что такое "calc" в других словарях:

    calc — CALC, calcuri, s.n. 1. (In sintagma) Hartie de calc = Hartie translucida obtinuta prin macinarea fina a pastei de hartie, folosita la executarea desenelor in tus, pentru a fi apoi copiate pe hartie heliografica (ozalid). 2. Copia pe hartie de… … Dic?ionar Roman

    Calc — may refer to:* OpenOffice.org Calc * Short for calculation, calculator, calcarea or calculus * The Anglo Saxon ? rune, representing /k/. * Microsoft Calculator, also known by it s filename calc.exe. See also * Calque … Wikipedia

    Calc — als Abkurzung fur Calculator (engl. fur Taschenrechner) bezeichnet die folgenden, mathematisch bezogenen Programme: OpenOffice.org Calc, die Tabellenkalkulation aus dem freien Buropaket OpenOffice.org KCalc, der Taschenrechner fur den Desktop KDE … Deutsch Wikipedia

    Calc — Calc: OpenOffice.org Calc табличный процессор, входящий в состав пакета офисных приложений OpenOffice.org. Калькулятор (Windows) (calc.exe) программа Microsoft Windows, исполняющая действия калькулятора. См. также Калькулятор (значения) … Википедия

    Calc- — vor Konsonanten auch Cal. Calci [lat. calx, Gen. calcis = Kalk (vgl. Calcium)]: Bestimmungswort von Zus. mit der Bed. »aus Kalk[stein], zu Calcium gehorig«, z. B. Calciferole, Calcit, Calsequestrin … Universal-Lexikon

    calc — Mot Monosil·lab Nom masculi … Diccionari Catala-Catala

    calc — Mot Monosil·lab Nom femeni … Diccionari Catala-Catala

    calc — calc·spar; … English syllables

    Calc — OpenOffice.org Calc Pour les articles homonymes, voir Calc (homonymie). OpenOffice.org Calc … Wikipedia en Francais

    Утилита iCACLS в Windows 7

    Утилита iCACLS в Windows 7

    Ранее в статье Утилита CACLS мы уже рассматривали утилиту, которая позволяет в командной строке изменять владельца файла или папки. Но CACLS актуальна лишь для Windows XP. В Windows 7 ей на смену пришла утилита iCACLS, принцип работы которой во многом не изменился.

    В целом, синтаксис команды icacls выглядит следующим образом:

    icacls папка\файл /setowner Пользователь параметры

    Посмотрим несколько конкретных примеров, как можно изменить владельца файла или папки.

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

    • /Q – сообщение об успешном выполнении команды не выводится;
    • /L – команда выполняется непосредственно над символической ссылкой, а не конкретным объектом;
    • /C – выполнение команды будет продолжаться несмотря на файловые ошибки; при этом сообщения об ошибках все равно будут отображаться;
    • /T – команда используется для всех файлов и каталогов, которые расположены в указанном каталоге;

    А вот как можно изменять разрешения для файла или папки:

    На этом возможности icacls не исчерпываются. Чтобы узнать больше, введите в командной строке команду icacls /? и вы получите полный перечень ее команд.

    Icalc

    Calc - Электронные таблицы

    Calc - программа для работы с электронными таблицами на персональных ЭВМ, в которой можно производить вычисления с использованием данных с числами, цифрами, значениями даты и времени, текстами и т.д. сохраняя электронные таблицы в долговременной памяти и отправляя таблицы либо публикуя их в Интернет.

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

    100 миллионов человек загрузило Открытый Офис через Интернет на свои домашние, офисные компьютеры в корпорациях, школах, вузах, фирмах и государственных учреждениях для работ по Программам Электронного Правительства.

    Базовые сведения об электронных таблицах

    Документ электронной таблицы По умолчанию состоит из трех листов: Лист1. Лист2 и Лист3. В каждом листе содержится максимум 65536 строк и 1024 столбцов. Строки помечены цифрами, а столбцы буквами. Пересечение строки и столбца называется ячейкой.

    Ячейка имеет свой адрес, состоящий из букв столбца, за которым следует номер строки ячейки. Например, ячейка, которая находится на пересечении столбца A и строки 2. имеет адрес A2. Диапазон ячеек в столбцах от A до C и строках от 1 до 5 имеет адрес A1:C5 .

    В адресе ячейки или диапазона ячеек можно также указать имя файла и имя листа. Ячейке или диапазону ячеек можно присвоить имя, чтобы можно было использовать имя вместо адреса столбца/строки. Подробную информацию ищите в справке приложения с помощью соответствующих терминов.

    Создание электронной таблицы

    Чтобы создать новую электронную таблицу в любой программе StarOffice, выберите Файл->Создать->Электронную таблицу.

    Навигация по листу

    С помощью мыши или клавиатуры можно перемещаться по листу Calc и выбирать элементы в таблице.

    Навигация по листу с помощью мыши

    Используйте горизонтальную или вертикальную полосу прокрутки для перемещения по таблице любую сторону.

    Навигация по листу с помощью клавиатуры

    Чтобы переместиться на одну ячейку вправо, нажмите стрелку вправо или Tab.

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

    Выбор ячеек на листе

    Ячейки на листе Calc можно выбирать с помощью мыши или клавиатуры.

    Чтобы выбрать диапазон ячеек с помощью мыши, щелкните ячейку и перетащите указатель в другую ячейку. Чтобы выбрать только одну ячейку, щелкните ячейку, удерживая Shift. Чтобы выбрать всю строку или столбец, щелкните метку строки или столбца. Чтобы выбрать все ячейки, нажмите кнопку над строкой 1 и слева от столбца A.

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

    Ввод данных

    Легче всего добавить данные в лист путем набора на клавиатуре или копирования и вставки из другой таблицы Calc или другой программы.

    Ввод данных в электронной таблице

    Щелкните ячейку, в которую требуется добавить данные.

    Введите данные. Или наберите данные на клавиатуре, или выберите Правка->Вставить, чтобы вставить данные из буфера обмена в ячейку.

    Нажмите клавишу Ввод. Можно также нажать клавишу со стрелкой, чтобы ввести данные и переместиться в следующую ячейку в направлении стрелки.

    Быстрый ввод последовательных дат и номеров

    В Calc предусмотрена функция заполнения, с помощью которой можно быстро ввести ряд последовательных данных, например дат, дней, месяцев и номеров. В каждой последующей ячейке вводится значение, увеличенное на один. 1 увеличивается до 2. Monday увеличивается до Tuesday и т.д.

    Щелкните ячейку.

    Введите первый элемент ряда (например, Monday ) и нажмите Ввод.

    Щелкните ячейку и перетащите метку-манипулятор заполнения, чтобы выделить диапазон ячеек, в которых требуется ввести весь ряд. Метка-манипулятор заполнения представляет собой небольшой черный квадрат в нижнем правом углу ячейки.

    Отпустите кнопку мыши. Последовательные элементы в ряде автоматически добавляются в выделенные ячейки.

    Редактирование содержимого ячеек

    Можно отредактировать содержимое ячейки или диапазона ячеек на листе.

    Редактирование содержимого ячеек на листе

    Щелкните ячейку или выберите диапазон ячеек.

    Чтобы отредактировать содержимое одной ячейки, дважды щелкните ячейку и внесите необходимые изменения.

    Совет – Можно также щелкнуть ячейку, внести изменения в строке ввода на панели Формула и нажать зеленую галочку. Однако если требуется ввести несколько строк текста, разделенных разрывами строк, то необходимо дважды щелкнуть ячейку и отредактировать содержимое непосредственно в ней. Нажмите Control-Ввод, чтобы вставить разрыв строки. Невозможно ввести разрыв строки в строке ввода.

    Calc придает введенным данным наиболее подходящий формат. Если введенные данные выглядят, как число, то Calc придает им формат числа. То же самое относится к введенным данным, которые больше похожи на дату и время. Начните вводить данные с одинарной кавычки ('), если не требуется автоматически преобразовывать данные в число или дату.

    Нажмите клавишу Ввод.

    Чтобы удалить содержимое ячейки или диапазона ячеек, нажмите клавишу Backspace или Delete. При нажатии Backspace удаление происходит сразу, а при нажатии Delete сначала открывается диалоговое окно.

    Форматирование электронных таблиц

    Можно форматировать лист вручную или с помощью стилей. Форматирование вручную применяется только к выбранным ячейкам. Форматирование с помощью стилей применяется во всех местах в электронной таблице, где используется этот стиль.

    Форматирование ячеек с помощью функции Автоформат

    Легче всего отформатировать диапазон ячеек с помощью функции Автоформат Calc.

    Применение автоматического форматирования к диапазону ячеек

    Выберите диапазон ячеек, который требуется отформатировать. Выберите диапазон по крайней мере 3 × 3 ячейки.

    Выберите Формат->Автоформат. Открывается диалоговое окно Автоформат.

    В списке форматов выберите формат, который требуется использовать, и нажмите кнопку ОК.

    Форматирование ячеек вручную

    Чтобы применить простое форматирование к содержимому ячейки, например изменение размера текста, воспользуйтесь значками на панели инструментов Форматирование.

    Форматирование ячеек с помощью панели инструментов Форматирование

    Выберите ячейку или диапазон ячеек, который требуется отформатировать.

    На панели инструментов Форматирование щелкните значок, соответствующий форматированию, которое требуется применить, или выберите настройку в выпадающем списке Шрифт или Размер шрифта.

    Применение форматирования вручную в диалоговом окне Формат ячеек

    Если требуются дополнительные настройки форматирования, кроме представленных на панели инструментов Форматирование в программе Calc, воспользуйтесь диалоговым окном Формат ячеек.

    Выберите ячейку или диапазон ячеек, который требуется отформатировать, затем выберите Формат->Ячейки. Открывается диалоговое окно Формат ячеек.

    Перейдите на одну из закладок и настройте параметры форматирования.

    Закладка Числа

    Настройки форматирования чисел в ячейках, например десятичный разряд отображаемых дробей

    Закладка Защита ячейки

    Настройки защиты содержимого ячеек на защищенных листах.

    Нажмите кнопку OK.

    Форматирование ячеек и листов с помощью стилей

    В программе Calc форматирование ячеек и листов по умолчанию осуществляется при помощи стилей. Стиль — это набор настроек форматирования, который определяет вид содержимого ячейки, а также структуру листа. При настройке форматирования в стиле изменения применяются во всех местах в электронной таблице, где используется данный стиль.

    Применение форматирования в окне Стили и форматирование

    Чтобы изменить форматирование ячеек, выполните следующие действия: Щелкните ячейку или выберите диапазон ячеек.

    Щелкните значок Стили ячейки в верхней части окна Стили и форматирование.

    Чтобы изменить структуру листа, выполните следующие действия: Щелкните в любом месте на листе.

    Дважды щелкните стиль в списке.

    Использование формул и функций

    В электронную таблицу можно вставлять формулы для выполнения вычислений.

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

    Создание формул

    Формула начинается со знака равенства (=) и может содержать значения, адреса ячеек, операторы, функции и константы.

    Создание формулы

    Icalc

    expression A mathematical expression, the result of which is used as the value.

    Expressions

    The expression can be any simple expression combining the following operators, using standard operator precedence rules:

    + Addition. - Subtraction. * Multiplication. At least one of the arguments must be a <number>. / Division. The right-hand side must be a <number>.

    The operands in the expression may be any length syntax value. You can use different units for each value in your expression, if you wish. You may also use parentheses to establish computation order when needed.

    Note: Division by zero results in an error being generated by the HTML parser.

    Note: The + and - operators must always be surrounded by whitespace. The operand of calc(50% -8px) for instance will be parsed as a percentage followed by a negative length, an invalid expression, while the operand of calc(50% - 8px) is a percentage followed by a minus sign and a length. Even further, calc(8px + -50%) is treated as a length followed by a plus sign and a negative percentage.

    The * and / operators do not require whitespace, but adding it for consistency is allowed, and recommended.

    Formal syntax Positioning an object on screen with a margin

    calc() makes it easy to position an object with a set margin. In this example, the CSS creates a banner that stretches across the window, with a 40-pixel gap between both sides of the banner and the edges of the window:

    Automatically sizing form fields to fit their container

    Another use case for calc() is to help ensure that form fields fit in the available space, without extruding past the edge of their container, while maintaining an appropriate margin.

    Here, the form itself is established to use 1/6 of the available window width. Then, to ensure that input fields retain an appropriate size, we use calc() again to establish that they should be the width of their container minus 1em. Then, the following HTML makes use of this CSS:

    Загружайте MS iCalc для iPhone

    A “must have” for every mass spectroscopist, MS iCalc is a collection of handy mass spec calculators designed to help you quickly get numbers and information you use every day, like mass and mass/charge, elemental composition, isotope patterns, m/z values, peptide modifications, and much more.

    Here’s the complete list:

    • Chemical Formula: Enter an elemental formula on the “periodic table” keyboard, and view its mass, mass/charge, and other properties.

    • Isotope Pattern Graph: View a zoomable graphical display showing a molecule’s isotope pattern, and specify multiple formulas to determine what resolution is required to separate them.

    • Isotope Pattern Table: View a molecule’s isotope pattern.

    • Elemental Composition: Enter an experimental m/z and a mass accuracy to view a list of matching elemental formulas.

    • Peptide Sequence: Specify a peptide sequence (with optional modifications) to view its mass and mass/charge.

    • Peptide Fragments: Enter a peptide sequence and calculate the m/z values of MS/MS fragment ions. You can choose which fragment types (y, b, etc.) to use.

    • Amino Acids: View the names, symbols, and masses of the amino acids.

    • Peptide Modifications: List available peptide modifications with their name, symbol, and mass shift.

    • Weight / Volume Conversion: Convert from one set of weight or concentration units to another.

    Общие сведения о COM - Delphi Sources FAQ

    Общие сведения о COM

    Автор: Fantasist

    Хотел я в общих словах расказать основную идею СOM. Когда я понял, что это такое показалась такая простая вещь, что можно коротко рассказать. Но не получилось. Что ж, будет немного подлиннее.

    Итак, попробуем рассказать в простоте. Вот есть у вас класс - примитивный калькулятор:

    Все элементарно. Теперь если у вас есть объект этого класса, то вам не составит труда им воспользоваться. Но представим следующую ситуацию: у вас есть один модуль, где объявлется объект этого класса. Допустим:

    и теперь вы хотите использовать в другом модуле. Хорошо, скажите Вы, мы его просто подключим, и используем. Но, допустим, вы хотите, чтобы и другие могли пользоваться вашим объектом, даже используея другой компилятор. То есть нужно сделать так, чтобы ваш модуль можно было бы использовать без перекомпиляции. Как это сделать? Ясно, что без каких-то стандартов не обойтись. Скорее всего, самый простой вариант выглядел бы так:

    откомпилировать этот юнит, посмотреть, по какому адресу находятся функции SetOperands, Sum, Diff, CreateObject и ReleaseObject и приложить документацию где эти адреса будут указанны. Теперь каждый сможет загрузить ваш модуль в память и по адресу указанном в вашей документации вызвать нужную функцию.

    Понятно, чем такой подход череват. Это крайне не удобно. Но, эта проблема была поставленна давно, и теперь у нас есть стандартизированное соглашение об экспорте функций. То есть вместо того, чтобы писать для каждого модуля документацию с адресами функций при компиляции в заголовке модуля создается специальная стандартная таблица где указанны имена этих функций и их адреса (также указывается числовой индефикатор, который может быть использован вместо имени). Теперь уже лучше. Для того чтобы вызвать ваши функции, достаточно загрузить ваш модуль в память прочитать таблицу экспорта, и можно по именам в ней нати адреса функций и их вызвать. Так устроены DLL. Сейчас все это поддерживается компиляторами, и Windows API. То есть вам самому ничего этого делать не надо, а достаточно вызвать LoadLibrary, чтобы загрузить ваш модуль в память, и GetProcAddress чтобы получить адрес функции по имени.

    Ура. До нас и за нас все уже стандатизировали. Давайте этим воспользуемся и напишим теперь наш модуль в постандарту. Напишим dll.

    Напишим программку - протестировать наш модуль.

    Классно! Теперь каждый программирующий в системе Windows на любом языке может использовать наш калькулятор! Что? Разочарованны? Такое ощущение что COM тут и не пахнет?

    Правильно, ибо про СОМ я пока ничего и не сказал, но Продолжение следует!

    Еще шаг в направлении COM

    Сделаем еще шаг в направлении Component Object Module (COM).Даже сейчас у экспортируется довольно много функций. Соответсвенно и в программе нам надо сделать несколько ступений - создать переменную-указатель, присвоить ей значение адреса нужной функции при помощи GetProcAddress, и только потом вызвать саму функцию. Причем все эти функции у нас сами по себе и никак не связанны с самим объектом, который мы используем. А неплохо бы сделать так, чтобы можно было работать с ними как с объектом, что нибудь типа:

    Так давайте так и сделаем! Правда мы ограничены экспортом только функций, но мы сделаем так: Добавим в dll такую запись

    и процедуру:

    и будем экспортировать только ее:

    Видете что происходит? Теперь вместо того, чтобы получать адрес каждой функции, мы можем получить сразу всю таблицу адресов. Причем создание объекта происходит в этой же функции, и пользователю больше не нужно знать функцию CreateObject и не забыть ее вызвать.

    Переделаем наш тестер. В описание типов добавим:

    изменим секцию var

    и процедуры где мы используем наш объект

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

    Понятие интерфейса

    Тут наконец проявляется одно из ключевых понятий COM - интерфейс(interface). Наша запись ICalc - это он и есть. То есть интерфейс - это таблица содержашаяя указатели на функции. Когда вы работаете с COM объектом, несмотря на то, что это выглядит так, как будто вы работаете с самим объектом, вы работаете с его интерфейсами. Реализация здесь может быть разная, это может быть указатели на внешнии функции, как это сделанно у нас (так практическм никто не делает), но чаще всего это указатели на методы класса. Пользователя это не волнует - он получает интерфейс и с ним работает, а уж ваша задача потрудиться над тем, чтобы работа с вашим интерфейсом проходила корректно.

    Мы можем создать несколько интерфейсов. Допустим, добавим в наш класс две функции:

    ну и придется добавить еще две внешнии функции:

    и переделаем GetInterface

    Теперь пользователь может ввести какой он хочет интерфейс сложение/вычитание или умножение/деление и получить соответсвующую таблицу методов.

    Слышу, слышу. Читатели уже начинают замечать сколько несуразностей в нашем коде. Давайте попробуем приводести его в нормальный вид.

    Во первых, неплохо бы избавиться от внешних функций. Сейчас нам приходилось на каждый метод нашего класса добавлять еще одну внешнюю функцию, чтобы этот метод вызывать. Почему мы не можем передпть указатели на методы класса? Дело в том, что указатель на методы класса должен содержать в себе также и указатель на экземпляр класса, чтобы метод мог обращаться к членам этого класса. В Делфи можно задать указатель на функцию класса:

    Такое обявление увеличивает размер указателя с 4 до 8 байт, что позволяет хранить в нем указатель на экземпляр класса. В принципе, возможно этим воспользоваться и описать процедуры нашего интерфейса как объектные, но это не будет шаг в сторону COM. Так как COM должен обеспечивать единый стандарт в нем используются указатели стандартного размера 4 байта. Как же нам все-таки избавиться от неудобных внешних функций? В разных средах разработки это может быть реализованно по разному, но раз уж мы начали с Delphi, рассмотрим как это реализованно в нем.

    В Delphi вводиться ключевое слово - interface. Объявление инерфейса - это и есть объявление таблицы методов. Выглядит это так

    GUID - необязательное поле индефицируеющая интерфейс. Тут надо сказать, что GUID(он же UUID, CLSID) - это 128-битное число, алгоритм генерации которого гарантирует его уникальность во вселенной. В Windows его можно получить функцией CoCreateGuid или UuidCreate. В Делфи это очень удобно встроенно в среду, и вы его можете получить нажав Ctrl+Shift+G.

    В нашем простом случае это будет выглядить так:

    Объявленный таким образом интерфейс можно прицепить к классу. Причем заметье, что методы интерфейса имплементируются только в классе, к которому они прицеплены. То есть вот так вы написать не можете:

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

    Все методы класса у нас уже имплементированны, кроме Release. Ну с ним все понятно:

    По умолчанию, методы привязываются по именам. То есть если в ICalc указан метод Sum, то компилятор будет искать метод Sum в классе MyCalc. Однако вы можете указать явно другие имена. Например:

    В нашем случае, удобно промаппить метод Release к методу Free, это избавит нас от необходимости имплементировать Release в нашем классе.

    Что же происходит при добовлении к классу интерфейса? Здесь для каждого экземпляра нашего класса создается специальная таблица(interface table), в которой храняться все записи о поддерживаемых интерфейсах. Каждая такая запись содержит адрес соответствующего интерфейса, который в свою очередь, как уже было сказанно является таблицей методов. То есть если мы получим адрес, допустим, нашего ICalc, то вызывая функцию по этому же адресу, мы вызовем метод SetOperands класса MyCalc. Ecли вы вызовете вызовете функцию по адресу +4 то вызовется метод Sum. Еще +4 байта будет метод Diff. То есть как вы видете, здесь указатели на функции имеют размер 4 байта, и адрес нужной функции получают прибавлением нужного смещения к адресу интерфейса. Получить же адрес нужного интерфейса можно с помощью метода GetInterface класса TObject.

    Забудем пока, что мы делали два интерфейса, и вернмся к варианту с одним интерфейсом. Перепишим наш GetInterface.

    Мы воспользовались методом GetInterface, который вышлядит так:

    этот возвращает в параметре Obj указатель на интерфейс, по указанному индификатору GUID. Допускается вместо переменной типа TGIUD поставить имя интерфейса - компилятор сам подставит его GUID если он ему известен.

    Все. Выбрасывайте все внешнии функции, кроме GetInterface. Теперь нам придется сказать спасибо Borland'у и сделать несколько дополнительных действий. Дело в том, что по стандарту COM каждый COM объект должен имплементировать интерфейс IUnknown. Он содержит три метода и выглядит так:

    Хочу еще раз отметить, что эти примеры пишутся для Делфи, однако суть от этого не меняется. Как бы не выглядил интерфейс в других средах разработки, он всегда остается таблицой с адресами функций. И если говорить о IUnkown, то он всегда должен содержать эти же методы, в этом же порядке. В С++ он например выглядит так:

    Так вот, в Delhpi все интерфейсы наследуются от IUnknown. Так что и наш интерфейс тоже содержит эти методы, а значит и компилятор потребует от вас их имплементации. Ну что ж. Добавтье пока пустые методы QueryInterface, _AddRef и _Release, позже мы их имплементируем правильно.

    Теперь не забудтье поменять тип ICalc на интерфейс в тестере, и убедитесь, что все работает. )

    Понятие интерфейса 2

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

    Tак ICalc2 будет содержать в себе все методы ICalc. Нам Sum и Diff в этом интерфейсе не нужны, так что давайте лучше напишим так:

    Теперь добавим его в наш объект.

    Опять возмемся за наш GetInterface. В принципе, мы могли бы оставить выбор интерфейса как было у нас раньше - передаем в GetInterface целую переменную и если она равна 1 то возвращаем ICalc, а если 2 то ICalc2. Но уж коли мы связались с COM, то давайте будем, по возможнсти, к нему приближаться. Сделаем полную аналогию GetInterface в TObject:

    Вуоля! Чуствуется, насколько теперь лучше, чем было вначале? Теперь если запрашиваемый инерфейс нашим объектом не поддерживается, то во-первых, мы даем клиенту об этом узнать, возвращая в Calc nil ( TObject.GetInterface это делает) и возвращая False из функции, а во- вторых, мы сразу же освобождаем объект. Но на самом деле, то что во-вторых, ничего хорошего нет, ибо мы подходим к следующей проблеме. Функцию мы обозвали GetInterface, но она еще и объект создает! А если пользователь захотел получить вначале ICalc, а потом ICalc2? Так как ему известна лишь функция GetInterface, он может воспользоваться только ей и получит два объекта, вместо двух интерфейсов одного объекта. Значит нужно отделить функции создание объекта, от получение его интерфейса. Давайте попробуем это сделать. Первая попытка:

    Хм. Не работает, не правда ли? Если клиент сделает так:

    то он получит интерфес второго созданного объекта, тогда как первый объект будет навсегда утерян. Что же надо сделать? Надо сделать так, чтобы CreateObject возвращала бы чего-нибудь, чтобы мы могли индифецировать объект, и получать имено его интерфейсы. Как я уже сказал, клиент работает с COM объектом только через его интерфейсы, значит логичнее всего при создании объекта вернуть интерфейс созданного объекта(точнее, указатель на него). Для нашего случая, можно возвращать указатель на ICalc, но можно облегчить жизнь ползователю, и попросить его указать, какой интерфейс он хочет.

    Здесь если интерфейса, который пользователь попросит нас нет, мы вернем nil и удалим объект. Если интерфейс есть, то пользователь сам будет удалять объект через метод Release. Неплохо, не правда ли? Теперь глобальная переменная Calc нам не нужна - мы создаем много обектов динамически.

    Ну теперь совсем очевидно, что если ползователь захочет еще один интерфейс этого объекта, то логичнее всего у этого объекта этот интерфейс и поросить. Вот мы уже влотную подошли к имплементации IUnknown - основного интерфейса в COM. Как я уже сказал, все объекты должны имплементировать IUnknown, и все интерфейсы должны быть потомками IUnknown(что Borland и сделал). Так что вы помните, что и оба наших интерфейса ICalc и ICalc2 являются потомками IUnknown, а значит и первые три метода, которые они содержат - это QueryInterface, AddRef, Release. Помните, я предлагал вам оставить эти три метода пустыми? Давайте сейчас имплементируем один из них - QueryInterface:

    HResult это тоже, что и Longint, только его значение определятся соглашением принятым в COM.

    Собираем тестовый пример

    Теперь, давайте соберем код. Прошу учесть, что практически не делается никаких проверок - это демонстрационный код. Но работающий.

    В начале код dll c объектом.

    А теперь тестер

    Обратите вснимание, что происходит при нажатии на кнопку3. Мы используем ту же самую переменную, для работы со вторым интерфейсом! Этот пример показывает, что получая указатель на интерфейс, его методы мы получаем за счет смещения, от адреса который этот указатель содержит. Короче, мы получаем адрес таблицы методов. Потыкайте, посмотрите что происходит.

    Стандарт СОМ

    Продолжаем, осталось совсем немного, чтобы подогнать под стандарт COM. Какой у нас пробел еще остался? Представте, что кто-то сделал так:

    Не очень хорошо, не правда ли? Нужно все-таки сохранить объект, пока им кто-то пользуется. Очевидное решение - подсчет ссылок. То есть, если у нашего объекта попросили интерфейс, мы увеличим счетчик, если кому-то интерфейс больше не нужен, мы ументьшим счетчик, и как только он обратиться в 0 мы уничтожим объект. Вот и настала пора, имплементировать последние два метода в интерфейса IUnknown. Вначале, добавим счетчик в наш объект:

    и имплементируем методы:

    Именно так, как правило, выглядят эти два метода в реализациях под Windows. Теперь в нашем интерфейсе Release не нужен, и можно его оттуда выкинуть. Итак, клиент должен вызывать Release для того, чтобы дать объекту знать, что он его больше не будет использовать, а кто должен вызывать AddRef? Во-первых, мы сами, всегда, когда клиент получает от нас интерфейс. Если бы мы не писали на Delphi, это надо было бы делать в методе QueryInterface, однако в Delhpi метод GetInterface класса TObject сам вызывает AddRef, так что нам заботиться об этом не надо. Надо сказать, что и клиент может вызвать AddRef, ecли по каким-то причинам, не желает чтобы объект исчез из памяти. Но тут уж вся ответсвенность на нем. Надо сказать еще об одной особенности Delphi, касательно использования COM объектов(а точнее интерфейсов) в своих приложениях. Как было упомянуто выше, клиент должен вызывать Release для того, чтобы объект знал, когда ему можно удалиться. Так вот для переменных типа interface Delphi сам вызывает Release, если переменная уничтожается или если ей присваивается nil. То есть:

    Так что всегла имейте это ввиду: как минимум один раз Release будет вызван без вашего указания.

    Ну вот у нас теперь практически полноценный COM объект. Чем же он еще не полноценен? Наверно вы уже догадались - он не универсален с точки зрения системы. То есть создать его можно лишь подключив загрузив вручную нашу dll и вызвав CreateObject. Но ведь в Windows есть возможность вызывать СOM объекты даже просто по имени! Как это делается? Понятно, что в системе существует правило, как создавать COM объекты. И если мы хотим, чтобы система знала как слздать наш MyCalc, мы должны сделать его по этим правилам. Именно этим мы и займемся.

    Но в начале, небольшое резюме. Итак СOM - это битовый стандарт, то есть он обеспечивает совместимость на битовом уровне. С СOM объектами работают через их интерфейсы. Интерфейс - это таблица методов, указатель на которую мы можем получить у объекта. Каждый СОМ объект имплементирует интерфейс IUnknown, который содержит три метода: QueryInterface, AddRef и Release (это стандартные имена, но в принципе вы можете дать любые. Так как совмещение идет на битовом уровне, то важен лишь порядок в котором расположенны эти методы в таблице, а так же тип метода(набор параметров, тип возвращаемого значения, тип вызова)). Все интерфейсы должны быть потомками IUnknown, то есть у каждого интерфейса первые три метода это QueryInterface, AddRef и Release. Интерфейсы индифецируются GUID. Для того, чтобы получить у объекта какой-то интерфейс, нужно знать его(интерфейса) GUID. То есть название интерфейса неважно для COM - оно исползуется для удобства людей. Вы можете назвать его IMyInterface, но если его GUID равен <00000000-0000-0000-C000-000000000046>, то все в COM'e (случайная игра слов) будут думать, что это IUnknown.

    Ну вот в основном все, пойдем дальше.

    Как система создаёт объект СОМ

    Итак, давайте посмотрим как система создает СОМ объект. (Все, что написанно далее про создание СОМ объекта, не является стандартом СOM, а является поддержкой работы COM системой. То есть так поддержка реализованна в Windows. В других системах поддержка COM (если вы ее там найдете) может быть реализована по другому.) Наиболее часто используемая API функция в Windows для создания СОМ объекта это CoCreateInstance (все названия функций Win API для работы с СОМ имеют префикс Со). Выглядит она так:

    Давайте запишим ее в паскалевском виде, и прокомментируем:

    Параметр dwClsContext указывает как должен быть создан объект. Если мы хотим создавать наш калькулятор c помощью CoCreateInstance этот параметр будет равен CLSCTX_INPROC_SERVER, то есть внутрипроцессорный сервер, так как наш объект находиться внутри dll и не может работать как отдельный процесс. Значит создание нашего объекта будет выглядеть примерно так:

    Итак у нас нет GUID нашего класса. Ну, его придумать не проблема, нажал в Delphi Ctrl+Shift+G и GUID готов (особо крутые программисты могут написать свою программку генерации GUID, которая будет сосотоять из одного вызова API функции СoCreateGUID или UuidCreate). А как система узнает о том, что этот GUID пренадлижит нашему классу? Правильно, пора заглянуть в реестр.Открываем ключ HKEY_CLASSES_ROOT\CLSID и видим длинный список GUID'ов. Именно в этом списке находятся все GUID зарегистрированных COM классов (GUID классов чаще называют CLSID - Class ID).При вызове CoCreateInstance в этом списке ищется тот GUID который равен параметру CLSID и если он находиться, то рассматривается параметр dwClsContext, и в соответсвии с ним ищется следующий подключ: если dwClsContext=CLSCTX_INPROC_SERVER ищется подключ InprocServer32 если dwClsContext=CLSCTX_INPROC_HANDLER ищется подключ InprocHandler32 если dwClsContext=CLSCTX_LOCAL_SERVER ищется подключ LocalServer32 и если он существует, то значение этого ключа будет указывать путь к модулю в котором находиться исполняемый код класса. Итак, чтобы зарегестрировать наш класс, нужно создать новый GUID (пусть это будет <2563AE40-AC27-11D6-A5C2-444553540000> ) и создать в реестре новый раздел HKEY_CLASSES_ROOT\CLSID\<2563AE40-AC27-11D6-A5C2-444553540000>, а в нем создать еще один подраздел InprocServer32 и в значение по умолчанию записать путь к нашей dll, у меня это C:\Kir\COM\SymplDll\CalcDll.dll. Отлично, теперь система знает где искать наш класс. Теперь давайте посмотрим как она этот класс создает.

    А создает она его так (сейчас мы говорим только о in-proc сервере).Найденная библиотека(dll) с классом загружается в память и в ней вызывается функция DllGetClassObject! Вот основная функция которую наша библиотека должна содержать, и через которую система и создает COM объект. Как она выглядит и что она должна делать? Выглядит она вот так:

    а делать она должна то, что делает сейчас наша функция CreateObject - создавать класс. По сравнению с CreateObject добавляется еще один параметр CLSID, так как библиотека может содержать больше чем один класс, то этот параметр указывает объект какого класса нужно создать. Если параметр CLSID содержит неизвестный нашей библиотеке GUID то функция должна вернуть CLASS_E_CLASSNOTAVAILABLE.

    Давайте перепишим наш CreateObject на DllGetClassObject:

    Итак, первой строчкой проверяем, является ли спрашевыемый индификатор класса(CLSID) индификатором нашего класса, который мы недавно придумали, с помощю Delphi, а далее как было раньше, пытаемся записать в переменную Obj указатель на интерфейс того интерфейса, GUID которого был нам передан в качестве параметра IID. Если такой интерфейс нашим классом не поддерживается, освобождаем объект и возвращаем ошибку. Если же все нормально, возвращаем S_OK, а в выходном параметре Obj будет находиться указатель на спрашиваемый интерфейс.

    Так же перепишим в тестере процедуру, где мы создаем наш COM калькулятор - это TForm1.FormCreate:

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

    Ну все. Все готово, теперь все компилируем и запускаем. Объект не создается! CoCreateInstance возвращает REGDB_E_CLASSNOTREG - класс не зарегестрирован. Но на самом деле ошибка не в том, что класс не зарегестрирован. А в чем? Давайте пройдемся пошагово по нашей dll. Поставим брекпойнт на первую линию функции DllGetClassObject. Мы видим, что эта функция вызывается, что CLSID соответсвует GUID нашего класса, что сам объект создается, но что дальше? Метод GetInterface не находит спрашеваемого интерфейса! Посмотрите чему равен параметр IID и вы увидите, что он не равен GUID интерфейса ICalc, который мы передавали CoCreateInstance, а равен он вот такому значению: <00000001-0000-0000-C000-000000000046>. Можно заглянуть в реестр Windows, чтобы узнать, что интерфейс с таким GUID носит название IClassFactory. Что ж, выходит CoCreateInstance просит не тот интерфейс, который мы предаем ей как параметр. Microsoft не скрывает реализацию CoCreateInstance - это, на самом деле, всего лишь вспомогательная функция и делает она следующее (вольный перевод на Delphi):

    Первой строчкой вызывается API функция CoGetClassObject, параметры у нее точно такие же как у CoCreateInstance, и как раз она является основной функцией - она находит библиотеку с классом и вызывает DllGetClassObject (опять же, это все для in-proc серверов). И как видите, она действительно просит интерфейс IClassFactory. Что бы понять, что делает следующая строчка, нужно рассмотреть еще один офицальный и широко известный интерфейс IClassFactory.

    IClassFactory

    Итак, IClassFactory предназначен для того, чтобы создавать экземпляры соответствующего класса. То есть строчкой:

    мы должны получить интерфейс, с помощью которого мы сможем создавать сколь угодно много наших калькуляторов (конкретнее: экземпляров нашего класса MyCalc). Для этого вызывается метод этого интерфейса CreateInstance. Параметры у него до боли знакомые - они точно такие же как три последних параметра у СoCreateInstance или CoGetClassObject. CLSID уже не нужен, так как данный интерфейс принадлежит классу, который создает только объекты определенного класса - того CLSID которого мы указали в СoCreateInstance, который потом передался в CoGetClassObject и который наконец попал в DllGetClassObject.

    Видете, тут довольно забавно получается - мы просим создать объект и выдать для этого объекта интерфейс IClassFactory, с помощью которого мы будем создавать эти же объекты. В принципе, мы совершаем лишнее действие, если собираемся создать только один объект, однако если мы хотим создать множество объектов, то такой путь более эффективен, чем многократный вызов CoCreateInstance или CoGetClassObject, поэтому он и был утвержден.

    Чисто теоретически, мы можем сделать так (для нашего калькулятора):

    Ибо IClassFactory, как и любой интерфейс, является потомком IUnknown, и поддерживает метод QueryInterface (как AddRef и Release, который Delphi вызывает автоматически). Единственная загвоздка состоит в том, что несмотря на то, что этот интерфейс вроде должен пренадежать только что созданному объекту MyCalc, во многих реализациях он ему не пренадлежит. Ну у нас то, конечно, пока еще вообще никакой реализации нет, но если бы это делал кто-то другой, то возможно он бы реализовал DllGetClassObject так:

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

    Мы же давайте пойдем другим путем, и просто дополним наш класс интерфейсом IClassFactory. Для этого мы можем сами создать интерфейс IClassFactory, как мы раньше создавали ICalc и ICalc2, а можем воспользоваться готовым описанием, включив в uses библиотеку ActiveX. Так оно выглядит там:

    Как видите, помимо CreateInstance здесь так же есть метод LockServer. Этот метод предназначен для того, чтобы гарантировать не уничтожение объекта. То есть поставили замок, и пока его не сняли, обект должен жить. Добавим и этот метод а наш класс.

    Реализация:

    Реализация CreateInstance полностью идентична последним восми строчкам функции DllGetClassObject - просто создаем объект и возвращаем интерфейс, если мы его поддерживаем. С LockServer тоже все просто: если fLock=true тогда увеличиваем счетчик вызовом _AddRef, иначе уменьшаем его вызывая Release.

    Ну теперь еще раз. Компилируем dll, тестер менять не надо, и запускаем. Свершилось! Наш калькулятор был создан системной функцией CoCreateInstance!