Новости
Карта сайта
Авторы
Поиск
Рассылки
Статьи и информация
VB хитрости
Популярные ошибки
Книги
Конференция
Программы
Контролы
Примеры
Разное
Ссылки

Статьи

COM в действии - II. Вопросы, вопросы, вопросы...

Количество просмотров: 16662 Автор: Файфель Б.Л.

В предыдущей статье на тему COM автор не рассмотрел ряд достаточно важных вопросов. Отчасти это было сделано умышленно - статья и так получилась слишком объемной. Настало время рассмотреть эти обойденные вниманием вопросы.
 
Начнем с отладки.
 

Как отлаживать ActiveX-Dll ?


Разработка серьезного программного обеспечения без отладочных средств - это своеобразный "экстрим". Применительно к теме статьи, проблема заключается в том, что ActiveX-Dll не запускаются сами по себе (как Exe-файлы). Поэтому для того, чтобы код ActiveX-Dll начал выполняться, нужно запустить Exe-файл, из которого и вызывать свойства и методы классов, содержащихся в ActiveX-Dll. Если же мы попробуем выполнять код этого Exe-файла в VB-отладчике, то внутрь объекта нам войти не удастся - для exe-файла ActiveX-Dll - это "черный ящик".
 
В принципе, отлаживать код ActiveX-Dll можно было бы так:
 
-вставить в исходники классов вывод отладочной информации (в тех местах, где это нужно) и скомпилировать ActiveX-Dll;
-создать проект (типа Standard-EXE), в котором создавать объекты из нашей ActiveX-Dll, запустить его на выполнение и наблюдать результаты.
 
Как организовать вывод отладочной информации? Можно выводить в текстовый файл, можно - непосредственно пользователю с использованием функции MsgBox... И то, и другое неудобно! Ведь операторы, обеспечивающие отладочный вывод, нужно будет потом убирать (хотя, можно для этого использовать условную компиляцию). Но самое печальное заключается в том, что при такой схеме разработчик теряет возможность использовать богатые возможности отладчика VB (точки останова, просмотр значений переменных и т.д.)
 
Можно поступить и по-другому - классы, которые планируется включить в состав ActiveX-Dll, отлаживать в составе обычного проекта. При этом отладчик остается с нами, но при создании Dll класс (классы) придется вручную переносить в другой проект. Это не слишком удобно (особенно, принимая во внимание, что отладка обычно выполняется несколько раз).
 
Более рациональный способ состоит в создании программной группы. Рассмотрим этот способ подробнее. Создадим простенький проект типа ActiveX-Dll. Переименуем проект в "tstDll", а класс "Class1" - в "myClass", и добавим к классу одно свойство (назовем его S1) типа Long и один метод "About". В область кода метода About занесем строку:
 
MsgBox "Наш класс!!!"
 
Если читатель для создания класса пользовался надстройкой Class-Builder, то получится что-то вроде:
'local variable(s) to hold property value(s)

Private mvarS1 As Long 'local copy

Public Sub About()

       MsgBox "Наш класс!!!"

End Sub

Public Property Let S1(ByVal vData As Long)
'used when assigning a value to the property, on the left side of an assignment.
'Syntax: X.S1 = 5

    mvarS1 = vData

End Property


Public Property Get S1() As Long
'used when retrieving value of a property, on the right side of an assignment.
'Syntax: Debug.Print X.S1

     S1 = mvarS1

End Property

 
Сохраним этот проект в заранее созданной директории (не компилируя!). Этот проект - наш основной объект отладки. Теперь займемся вызывающим проектом. Создадим новый проект (на этот раз - типа standard-Exe); добавим в него форму, разместим на ней две кнопки. На первой напишем "Запустить", а на второй - "Закончить". А затем назначим кнопкам следующие обработчики:
 
'::: Обработчик кнопки "Запустить"

Private Sub Command1_Click()

Dim m As tstDLL.myClass

    Set m = New tstDLL.myClass
    
    m.S1 = 7
    
    l& = m.S1
    
    m.About

End Sub

'::: Обработчик кнопки "Закончить"

Private Sub Command2_Click()

        End

End Sub

 
Внимательный читатель в этом месте воскликнет: "А как же мы можем ссылаться на класс tstDLL, ведь ActiveX-Dll еще не скомпилирована?" Терпение! Все сейчас выяснится.
Сохраняем этот проект в той же директории, что и проект tstDll. Теперь в меню "File" выбираем пункт "Add Project...":
 

Рис. 1
 
На появившемся окне выбираем закладку "Existing" (существующие) и в оглавлении нашей директории выбираем проект tstDll. Если все сделано верно, в окне Project Explorer должна быть такая картинка:
 

Рис. 2
 
Теперь - самое важное. Щелкаем по имени "Project1" правой клавишей мыши и в выпавшем меню выбираем пункт "Set As Start Up":
 

 
Рис. 3
 
У нас готова программная группа, состоящая из двух проектов: отлаживаемый (tstDll) и ведущий - Project1. Находясь в среде, мы можем открывать, просмотривать и модифицировать составные части обоих проектов. В частности, можно открыть модуль класса и задать нужные точки останова.
Войдем в модуль класса и поставим точки останова на операторах в процедурах Get/Let и метода About. Теперь смело запускаем ... что? Нашу программную группу. Просто щелкаем по треугольничку на панели отладки. При этом первым запустится именно Project1 (ведь мы только что установили ему свойство "Set As Start Up").
На экране возникнет главная форма этого проекта с двумя кнопками. Нажимаем кнопку "Запустить"... Произойдет останов в процедуре Let S1. Дальнейшее, как полагает автор, вполне ясно. Мы можем просматривать локальные и другие переменные, устанавливать и снимать точки останова, в общем, пользоваться всем богатством возможностей отладчика. Можно также вставлять в код операторы Debug.Print; при выполнении в составе группы результаты будут выводиться в окне "Immediate".
Можно объединять в группу и более двух проектов. А вот когда отладка закончена - самое время скомпилировать проект "tstDll" (уже как отдельный проект) и пользоваться полученным файлом tstDll.dll, как было описано в предыдущей статье.
 

А может ли быть зарегистрировано несколько Dll с одинаковым именем?


В процессе обсуждения первой статьи был поднят достаточно интересный вопрос: можно ли зарегистрировать на одном компьютере два или более одинаковых ActiveX-Dll? Автор, к сожалению, допустил неточность, на которую ему и было указано.
На самом деле две одинаковые (идентичные) ActiveX-Dll зарегистрировать не удастся: при регистрации второй Dll ее данные (собственно, только местоположение) будут занесены в системный реестр, а старое расположение будет затерто.
Но никто нам не запрещает (и не может запретить!) создать несколько Dll с одним и тем же именем, но разной "начинкой". Или даже с "одинаковой начинкой", но различающейся деталями. Такие Dll можно порознь зарегистрировать (естественно, в разных директориях). В этом легко убедиться.
Но, позвольте! - воскликнет читатель - Ведь в программе на VB/VBA мы для создания объекта используем конструкцию типа:
Set myObj = New Имя_Dll.Имя_класса

И как VB догадается, из какой библиотеки создавать класс (если в реестре представлены, например, три библиотеки "Имя_Dll", каждая из которых содержит класс " Имя_класса "!?
Ответ будет таким: никак не догадается! Этот выбор должен совершить программист, когда он устанавливает ссылку (Reference). На следующем рисунке приводится окно установки ссылок для проекта VB. Из рисунка отчетливо видно наличие трех библиотек с одинаковым именем "Calc" и двух - с одинаковым именем "Bservy":
 


Рис. 4
Программист должен выбрать нужную библиотеку (поставив против ее имени галочку). Попытка установить ссылки в одном проекте на две библиотеки с одним и тем же именем приведет к ошибке:
 


Рис. 5
 
Таким образом, при раннем связывании VB будет создавать объекты из заранее выбранной программистом библиотеки. Все это достаточно естественно.
А что будет при позднем связывании? Эксперименты показывают, что при наличии на компьютере двух или более библиотек с совпадающими именами активизироваться будет библиотека, сведения о которой расположены в реестре "выше".
Чисто языковых средств выбрать нужную библиотеку в VB нет. Здесь автор признается, что немного завидует приверженцам C++ - в этом языке COM-объект можно создать по его GUID-у (а имя библиотеки никакой роли не играет). А можно ли в VB создать класс по его GUID-у? Об этом - ниже?
 

Создаем COM-объект по его GUID-у.


 

Прежде, чем создавать объекты по их GUID-ам, давайте зададимся вопросом: как узнать GUID класса? Очевидно, что нужную информацию можно найти в реестре с помощью regedit (или другой подходящей программы).
 
А давайте научимся получать эту информацию сами! Это не так трудно, как может показаться на первый взгляд.
 
Для начала - немного сведений о том, какая информация о зарегистрированных COM-объектах хранится в реестре.
 
В ветви HKEY_CLASSES_ROOT\CLSID хранятся GUID-ы зарегистрированных библиотек. Отдельная ветвь выглядит примерно так:
 

 

Рис. 6
 

Как видно из Рис.6, в папке "ProgID" находится полное наименование класса в формате Имя_Библиотеки.Имя_Класса. Кроме папки "ProgID" нас интересуют еще папки "TypeLib", "VERSION" и "InprocServer32". В последней из них содержится полный путь к библиотеке (как это отмечалось в предыдущей статье):
 


Рис. 7
 
В папке "VERSION" содержится номер версии библиотеки, а вот в папке "TypeLib" содержится GUID библиотеки типов нашего класса:
 


Рис. 8
 
Кроме того, часть информации о классах хранится в ветви реестра HKEY_CLASSES_ROOT\Interface. Как следует из названия этой ветви, здесь хранятся сведения об интерфейсах. Это выглядит так:
 


Рис. 9
 
Обратите на то, что GUID, хранящися в папке TypeLib, в точности равен GUID-у из ветви HKEY_CLASSES_ROOT\CLSID (сравните рисунки 8 и 9).
 
Если читатель захочет покопаться в реестре самостоятельно, можно предложить следующую схему:
 
-запустить regedit.exe;
-в режиме поиска набрать "Имя_библ.Имя_класа". Первое вхождение будет зафиксировано в ветви HKEY_CLASSES_ROOT\CLSID.
-взять значение параметра TypeLib и занести в текстбокс окна поиска. Искать до тех пор, пока не попадете в ветвь HKEY_CLASSES_ROOT\Interface.
 
А мы напишем несложную программу, которая по идентификатору "Имя_библ.Имя_класа" (он называется ProgID) выдаст нам всю необходимую информацию из реестра. Следующий ниже текст никак не претендует на описание эталонной программы работы с ресстром. Работе с реестром в VB посвящено множество великолепных материалов.
 
При этом мы будем действовать по следующей схеме:
 
a)Открываем ветвь HKEY_CLASSES_ROOT\CLSID. Для этого нужно вызвать функцию RegOpenKeyEx с соотвествующими параметрами;
 
b) В бесконечном цикле перебираем все GUID-ы этой ветви. Очередной GUID берется вызовом RegEnumKeyEx. Когда этот вызов вернет ненулевой код завершения - считаем, что все GUID-ы классов (CLSID-ы, если угодно) исчерпаны;
 
c)Для каждого GUID-а класса берем его ProgID. Чтобы получить ProgId, открываем ветвь "CLSID\Очередной_GUID\ProgID" вызвав RegOpenKeyEx; Если вызов завершен удачно (нулевой код возврата), то вызываем RegQueryValueEx и получаем значение ProgID;
 
d)Проверяем, совпадает ли значение ProgID с тем идентификатором, который мы ищем. В прилагемой программе для этого используется оператор Like, что позволяет задавать при сканировании реестра не только конкретный ProgID, а шаблон, содержащий "*". После получения ProgID, нужно вызвать функцию RegCloseKey (закрытие ключа).
 
e)Если ProgID нам подходит, достаем GUID библиотеки типов (применив RegOpenKeyEx к ветви "CLSID\Очередной_GUID\TypeLib") и вызываем RegQueryValueEx для получения GUID-а библиотеки типов. Получив GUID, закрываем ключ (RegCloseKey).
 
f)Аналогичным образом получаем параметр InprocServer32
 
g)Повторяем пункты с) - e) до тех пор, пока не переберем GUID-ы всех классов, запоминая в рабочих массивах GUID-ы классов (CLSID-ы), GUID-ы библиотек типов, ProgID-ы классов и директории (InprocServer32).
 
h)Теперь для каждого класса необходимо просканировать ветвь "Interface\GUID_библ_Типов\TypeLib" и извлечь версию класса. Поскольку в этой ветви реестра может находиться информация о нескольких версиях класса, нам нужна последняя (т.е. c максимальным номером). Автор поступал так: брал один за другим GUID-ы интерфейсов (их еще называют IID-ами) и для каждого получал версию. Если она оказывалась больше предыдущей - запомнал IID и номер версии. Таким образом, когда ветвь
 
"Interface\GUID_библ_Типов\TypeLib"
 
i) просканирована полностью, мы получаем максимальный номер версии каждого класса и его IID.
 
j)Теперь осталось всю накопленную информацию показать пользователю:
 



Рис. 10
 
Полные исходные тексты этой программы прилагаются к этой статье. Работать с программой следует так:
 
- в поле "ID класса" задать шаблон поиска (Например, шаблон *.cBDF означает поиск класса cDBF во всех библиотеках);
 
- при необходимости сохранить результаты поиска в файле, поставить галочку "сохранить копию". Копия сохранится в текущей директории в файле Result.txt;
 
- нажать кнопку "Начать сканирование" и дождаться завершения.
 
Имея CLSID и IID класса, создать объект достаточно просто. Для этого служит вызов:
 
Declare Function CoCreateInstance Lib "ole32.dll" _
   (ByRef rclsid As Byte, _
    ByVal pUnkOuter As Long, _
    ByVal dwClsContext As Long, _
    ByRef riid As Byte, _
    ByRef ppv As Any) As Long

 
Самые важные параметры этой функции - rclsid и riid. Они представляют собой CLSID класса и IID интерфейса соответственно. Но вот незадача: GUID-ы должны представляться не как строки VB, а как байтовые массивы. Но ничего страшного! Microsoft о нас позаботилась: есть функция, которая преобразует строчную форму GUID-ов в нужную форму:
 
Declare Function CLSIDFromString Lib "ole32" _
        (ByVal lpsz As Any, _ 
         ByRef pclsid As Byte) As Long

 
Вот теперь уже ничто не помешает нам создать класс по его GUID-ам. Ниже приводится исходный текст функции, которая делает именно это:
 
Public Function ObjectCreate(CLSID As String, IID As String) As Object

Dim myObj       As Object
Dim IID_C1(15)  As Byte
Dim IID_C2(15)  As Byte

       Call CLSIDFromString(StrPtr(CLSID), IID_C1(0))  
       Call CLSIDFromString(StrPtr(IID), IID_C2(0))

       If Not (CoCreateInstance(IID_C1(0),0&,CLSCTX_SERVER,IID_C2(0), myObj) = 0&) Then
       
          Set myObj = Nothing
          
       End If
       
       Set ObjectCreate = myObj

End Function

 
Константа CLSCTX_SERVER имеет значение &H5 (в формате Long). Функция возвращает ссылку на объект (если его удалось создать) или значение Nothing в противном случае.
Автор прилагает к этой статье небольшую DLL-ку (с исходным текстом, разумеется!), которая позволит создавать в VB классы по их GUID-ам.
Вот теперь можно управлять выбором объекта и при позднем связывании. А это может быть полезно в средах, где раннего связывания нет в принципе (например, в VBScript-е). Программный код приводится ниже:
 
' сначала создаем порождающий объект 

Set MainObj=CreateObject("ObjByGuid.Create")

' пытаемся вызвать первую версию калькулятора

Set clnd=MainObj.ObjectCreate (Cstr("{F16DC27E-F6C6-11D9-82A9-00E04C0A8DCA}"), _
                             Cstr("{F16DC27D-F6C6-11D9-82A9-00E04C0A8DCA}"))

If clnd is Nothing then
   MsgBox "Ошибка!"
else
   clnd.About
end if 

' унитожаем первую версию

Set clnd=Nothing

' пытаемся вызвать вторую версию калькулятора

Set clnd=MainObj.ObjectCreate(Cstr("{221F0D43-0CC2-11DA-82A9-00E04C0A8DCA}"), _
                            Cstr("{221F0D42-0CC2-11DA-82A9-00E04C0A8DCA}"))
If clnd is Nothing then
    MsgBox "Ошибка!"
else
   clnd.About
end if 

' унитожаем вторую версию

Set clnd=Nothing

' уничтожаем порождающий объект

Set MainObj=Nothing

 
У автора на компьютере зарегистрированы две версии калькулятора из первой статьи (в разных, естественно, директориях). Классы называются одинаково. Библиотеки тоже называются одинаково. Приведенный выше скрипт позволяет запустить и первую и вторую версию. Необходимые GUID-ы получены с помощью порограммы regScan, описанной ранее. Чтобы выполнить этот скрипт, сначала нужно зарегистрировать на своей машине компонент ObjByGuid.dll (без этого не выполнится первый оператор скрипта).
 

А как, имея ActiveX-Dll, узнать список ее классов и интерфейс каждого класса? - Самодельный браузер объектов.


 
Ну, ладно? Создавать ActiveX-Dll, отлаживать и использовать их мы научились. Однако, остался вопрос, который мы еще затронули.
Есть зарегистрированная ActiveX-Dll. Работая в VB или VBA, мы можем посмотреть свойства и методы классов этой библиотеки в т.н. браузере объектов. Кроме того, если установлена ссылка на нашу библиотеку, то ассистент сред VB/VBA предлагает выбрать нужное свойство/метод из выпадающего списка прямо в среде разработки.
А откуда браузер объектов и ассистент получают всю эту информацию? Понятно, что из самого dll-файла.
Давайте попробуем выполнить эту же работу. Зачем? Во-первых, это интересно? А во-вторых, оставшись "один на один" с ActiveX-компонентом, мы сможем вытянуть из него всю необходимую информацию (почти) без посторонней помощи.
В конце концов, хранение сведений об интерфейсе класса в самой библиотеке классов и есть центральная идея COM. Итак, изучаем интерфейс COM-объектов!
COM задуман так, что кроме разработанных пользователем интерфейсов, каждый COM-объект обязательно содержит стандартный интерфейс (предназначенный для получения сведений об остальных интерфейсах) . Используя этот интерфейс (он для всех COM-объектов одинаковый), можно "раскрутить" весь интерфейс COM-объекта. Автору попадалось несколько статей на эту тему, но он не собирается воспроизводить здесь их содержание. Дело в том, что Microsoft и тут позаботилась о любителях VB (все же Б. Гейтс не зря подписывался "Bill Gates - Basic programmer"!). Есть стандартный ActiveX-компонент, который позволяет получить интерфейс любого COM-объекта. Имя библиотеки - TLBINF32.DLL. Если у читателя на компьютере установлен VB, то эта библиотека, скорее всего, тоже присутствует. А если нет - ее можно взять из прилагаемого к статье архива и зарегистрировать.
Основываясь на этой библиотеке мы сделаем т.н. минибраузер объектов - программу, которая возьмет объект и покажет его интерфейс.
Начинать следует с того, что созать новый VB-проект (стандартный EXE) и установить ссылку на библиотеку TLBINF32.DLL:
 

 



Рис 11
 

Теперь необходимо создать главный объект, который называется TLIApplication:
 
?
Dim appTLI As TLI.TLIApplication
?
Set appTLI = New TLIApplication

 
Далее, нужно создать ссылку на объект, интерфейс которого мы хотим изучить:
 
Dim obj As Object
?
Set obj = CreateObject(Me.Text1.Text)
?

 
Теперь, можно получить ссылку на интерфейс объекта:
 
Dim inte As InterfaceInfo
?
Set inte = appTLI.InterfaceInfoFromObject(obj)

 
Дальнейшее совсем просто. Объект, обозначенный "inte" содержит коллекцию Members - членов интерфейса. Работать с этой коллекцией можно обычным образом: Сначала возьмем Inte.Members.Count - число членов коллекции и организуем цикл по всей коллекции. При этом Inte.Members().Name - будет содержать имя очередного члена интерфейса. Это понятно. А вот Inte.Members().InvokeKind - это тип очередного члена (1 - метод; 2 - процедура Property GET; 4 - процедура Property LET). Значение inte.Members().ReturnType.VarType дает тип возвращаемого значения (для метода или свойства). Некоторые возможные значения этой величины (типа Long) дает следующая таблица:
Значение
ReturnType.VarType
Тип возвращаемого
значения
1 NULL
2 INTEGER
3 LONG
4 REAL
5 DOUBLE
8 STRING
11 BOOL
12 VARIANT
19 OLECOLOR
24 VOID

Замечание для читателей, совсем не знакомых с C/C++: для методов, не возвращающих значений ReturnType.varType будет равно 24 (VOID).
Осталось получить список параметров каждого из членов класса. Это тоже несложно. Каждый член коллекции Members содержит в своем составе коллекцию Parameters. Члены этой коллекции и есть параметры соответствующего метода. Конструкция inte.Members(i).Parameters(j).VarTypeInfo.VarType дает тип j-го параметра i-го метода.
Собирая все воедино, получаем самодельный (несовершенный, конечно!) браузер объектов. Интерфейс класса, отображенный в браузере, выглядит так:
 



Рис 12
Полный исходный текст минибраузера можно взять из архива, прилагаемого к этой статье.
Обратите внимание на то, что какой бы объект вы не взяли, три первых метода будут:

-QueryInterface
-AddRef
-Release

 
Это - незыблемая основа COM! Автор просит не удивляться, что Addref и Release возвращают тип OLECOLOR: ведь тип OLECOLOR - это обычный Long, просто называемый по-другому.

 

А где еще можно использовать COM? COM и Internet Explorer.


 

Что бы ни говорили недоброжелатели Microsoft, COM-модель - это реальный и работающий стандарт. COM-библиотеки (назывемые еще ActiveX-компонентами) можно использовать в самых разных программных средах.
Самой распростаненной программой Microsoft является без сомнения Internet Explorer. А можно ли использовать ActvieX-компоненты в среде Internet Explorer? Легко! Но есть один неприятный нюанс. Дело в том, что? А давайте сначала попробуем внедрить ActiveX-компонет в WEB-страницу и сами все увидим!
Стандарнтый способ внедрения ActiveX-компонентов в WEB-страницу предполагает использование тега <OBJECT>. В этом теге следует задать CLSID внедряемого объекта. Находить CLSID объекта мы умеем. Если объект зарегистрирован на клиентской машине (где запускается наша WEB-страница), все хорошо. Если же ActiveX находится где-либо в сети, можно указать URL соответствующего файла. В этом случае, Internet Explorer скачает указанный файл и зарегистрирует его на клиентском ПК. Здорово!
Попробуем внедить в Web-страницу разработанный нами же калькулятор. Создаем текстовый файл html_test.html:
 
<html>
<object ID=calc classid="clsid:804DEAAD-17F4-11DA-82A9-00E04C0A8DCA"
 border="0" width="0" height="0">
</object>

<p id=ShC onmouseover="this.style.cursor='hand'">Показать калькулятор</p>

<script language=vbscript>

Sub ShC_OnClick()

    calc.show

End Sub

</script>  
</html>

 
Мы собираемся отобразить калькулятор по щелчку мыши на надписи "Показать калькулятор". Конструкция OnmouseOver=? обеспечивает изменение формы курсора мыши при наведении на надпись.
Открываем созданный файл в Internet Explorer. Файл нормально отображается. Щелкаем по надписи "Показать калькулятор". Что это?
 


Рис 13
 
Ничего удивительного. Просто браузер предупреждает, что производится попытка вызвать посторонной код в среде Internet Explorer. Выполнение постороннего кода - опасная операция. Если пользователь нажимет кнопку "Нет", класс создан не будет. Читатель легко представит, в какой рассадник вирусов превратился бы Internet, если бы не было этого ограничения! В действительности Microsoft предоставляет возможность подписывать ActiveX-компоненты. При попытке загрузки компонента из сети выдается запрос "Доверяете ли вы разработчику компонента?" и т.д. и т.п. Но, как известно, безопасность обратно пропорциональна удобству. Поэтому реальная область применения ActiveX в Internet-е достаточно скромна - в основном это стандартные компоненты графического интерфейса - текст-боксы, выпадающие списки и т.д. А нестандратные ActiveX-компоненты можно применять в корпоративных интрасетях.
Есть, однако, не слишком широко известная возможность комфортного применения ActiveX в среде Internet Explorer - это т.н. HTA-приложения. Превратить наш html-документ в HTA-приложение очень просто: нужно всего лишь заменить расширение файла с html на hta. И все! При открытии hta-файла пользователь увидит картинку:
 


Рис 14
 
При щелчке на надписи будет отображен калькулятор. Без каких бы то ни было сообщений о безопасности. В HTA-приложениях можно использовать VBScript. Собственно HTA - это VBScript дополненный оконными средствами отображения. Впрочем, HTA следует сделать темой отдельной статьи (непосредственно к COM не относящейся). А вот использованию COM на WEB-сервере будет посвящена следующая (завершающая) статья.
Скачать все использованные в статье материалы можно здесь.

Добавлено: 26 февраля 2006

Отзывы читалелей

Machine

толково. Даже очень. Спасибо. Была как раз в тему проблема. Очень помогло.

A. Skrobov

>В ветви HKEY_CLASSES_ROOT\CLSID хранятся GUID-ы зарегистрированных библиотек.
Хотелось бы вновь обратить внимание на эту неточность: у библиотек нет CLSID. CLSID свой у каждого класса, которых в одной библиотеке может быть хоть сто.
На самом деле, как вы позже и отмечаете, GUID-ы зарегистрированных библиотек хранятся в ветви HKEY_CLASSES_ROOT\TypeLib



Добавить отзыв

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

Ваше имя:
Ваш E-mail:
Ваш комментарий:
 


К статьям

Rambler's Top100
Хостинг от Parking.ru