---------------------------------------------------------------  COM

1. Úvod na začátek

aneb motivace, proč se něčím takovým vůbec zabývat

1.1. Co COM je a co není

Podíváte-li se zběžně na nějaký program psaný dle COM, mohlo by se zdát, že tu máme opět další programovací jazyk odvozený od C++, či novou knihovnu pro práci ve Windows. Takže nošení dílů do Dallasu. Proto upozorňuji hned na začátku, že není tomu tak. COM není jazyk ani soubor objektů, ale pouze standard či programovací technika - nezávislá na programovacím jazyku a operačním systému. Přestože byl COM vyvinut pro prostředí Windows, lze v něm teoreticky programovat i v jiných operačních systémech - ale v praxi se tam s nimi nesetkáme, neb tam jsou standardem jiné objektové modely (např. CORBA)
COM určuje základní vlastnosti objektů a pravidla pro práci s nimi. Objekty v COM (tzv. komponenty) mezi sebou komunikují dle pevně stanoveného protokolu. COM je binární standard - knihovny psané dle COM mají i po zkompilování pevně danou strukturu, proto je lze použít i v jiném programovacím jazyce, než byly napsány.

1.2. COM, DCOM, CORBA, OLE...

Kolem objektových modelů se točí spousta zkratek, které si v tomto odstavci demystifikujeme.

COM+
Rozšíření standardního modelu COM. Obsahuje např. notifikaci událostí jiným objektům, propracovanější systém přístupových práv atd.
DCOM - Distributed Component Object Model
Rozšíření COM o komunikaci s objekty na vzdálených počítačích (pro distribuované aplikace).
CORBA - Common Object Request Broker Architecture.
Univerzální objektový model pro distribuované aplikace. Stanovuje obdobná pravidla, jako COM/DCOM, ale na rozdíl od nich není závislý na Windows. Pro aplikace běžící na více operačních systémech lze použít COM/DCOM jako jeho front-end pro Windows.
OLE - Object Linking and Embedding
Zatímco COM stanovuje základní vlastnosti objektů, OLE je jeho implementace pro komponenty ve Windows - dokumenty, ovládací prvky (controls) i samotné aplikace. Díky jednotné komunikaci mezi komponentami lze např. odeslat mail Outlookem ve wordovském makru.
ActiveX
Nástupce OLE. Umožňuje navíc např. integraci ovládacích prvků do webových stránek (které však tím pádem budou fungovat jen v Internet Exploreru)
ATL - Active Template Library
Vývojové prostředí ve Visual Studiu pro práci v COM. Mnoho "špinavé práce" udělá za vás.
WTL - Windows Template Library
Rozšíření ATL o COM objekty pro user-interface - ovládací prvky, běžné dialogy atd.

1.3. Proč používat COM?

Důvodů je více a všechny mají vznešeně znějící názvy:

Modularita
Lapidárně řečeno jde o to, aby jeden objekt (či spíše jeho programátor) se nemusel zabývat tím, co dělají objekty ostatní. Objekt má dané určité metody, pomocí nichž lze jím manipulovat. Objekt se v průběhu verzí může měnit, ale jeho rozhraní je stabilní - tj. deklarace metod se v nové verzi nemění, nanejvýš přibudou nějaké nové. Programátor má tudíž jistotu, že jeho program bude dělat to, co má, i v případě, že uživatel nainstaluje novější verzi knihoven.
Univerzálnost
čili nezávislost na programovacím jazyku. COM je ve své podstatě standard pro zkompilované binární soubory - proto jeho komponenty lze použít ve všech jazycích a kompilátorech, které umí vytvořit kód odpovídající COM standardu. Jediné požadavky na jazyk jsou, aby podporoval pointery a objektové programování.
Deklarace objektů a jejich metod se naopak řeší pomocí Interface Definition Language (IDL) - univerzálního deklaračního jazyka, který jednotlivé kompilátory snadno přeloží do svého jazyka.
Správa paměti
Zapomeňme na nealokované pointery, neuvolněnou paměť a podobné radosti programátorského života! Životní cyklus komponent se řídí tzv. referencemi - počtem pointerů, které na daný objekt ukazují. Klient pouze zvyšuje či snižuje počet referencí dle jednoduchých pravidel a klesne-li počet referencí na nulu, objekt se automaticky postará o vymazání sama sebe z paměti.

*) Tím nechci obhajovat Visual Basic - jsem samozřejmě přesvědčen, že Basic je vhodný pro výuku programování, ale psát v něm skripty je zhůvěřilost. Nicméně např. Microsoft Access vám nic jiného nenabídne (Na druhou stranu chválabohu, že tu nemáme Visual Karla...)

1.4. Jak se toho dosahovalo dříve

Nejjednodušší je samozřejmě prosté vložení zdrojového kódu (přes #include), ale to je u větších projektů velmi nepraktické. Kompilace programu trvá neúměrně dlouho, protože všechny vložené knihovny se kompilují pokaždé znovu. Navíc máme-li více programů využívajících tutéž knihovnu, v každém z nich je její kopie, což zbytečně plýtvá místem jak na disku, tak v RAM. A jakmile se zveřejní nová verze knihovny, je nutno překompilovat všechny programy, které ji využívají.
Statické knihovny (soubory .LIB) řeší pouze to, že jejich zdrojový kód je již předkompilován, takže kompilace celého programu netrvá tak dlouho. Ostatní problémy však přetrvávají.
S dynamickými knihovnami (soubory .so v Unixu či DLL ve Windows) by se zdálo, že jsme skoro za vodou. Dynamické knihovny se však nekopírují do zkompilovaného souboru, ale zůstávají jako samostatné soubory. Do paměti se nahrají až v okamžiku, kdy nějaký program hodlá využít jejich funkcí. V paměti však zůstává pouze jedna kopie knihovny, kterou využívají všechny programy společně. Protože jde o soubory ve strojovém kódu, stačí nahradit stávající knihovnu novou verzí a všechny programy budou automaticky používat novou verzi bez nutnosti rekompilace. To však může někdy vést k problémům, neb ač se knihovny honosí dynamickým přídomkem, jejich hlavičkové soubory se stále linkují staticky. Uvažujme následující objekt a jeho užití:

BearLibrary.h

class CBear
{
public:
	void EatHoney();

protected:
	int weight;
};
BearLibrary.cpp

#include "BearLibrary.h"

void CBear::EatHoney()
{
	weight += 20;
}
App.cpp

#include "BearLibrary.h"

int main()
{
	CBear* b = new CBear;
	b->EatHoney();
        ...
}

Všechno funguje bez problémů, medvěd si spokojeně pochutnává na medu, až jednoho krásného dne se rozhodneme upgradovat na vyšší verzi knihovny...

BearLibrary2.h

class CBear
{
public:
	void EatHoney();

protected:
	int weight, paw;
};
BearLibrary2.cpp

#include "BearLibrary.h"

void CBear::EatHoney()
{
	weight += 20 * paw;
}

...a program náhle začne "bezdůvodně" tuhnout. Proč? Protože v jeho kódu je stále obsažena deklarace třídy CBear ze staré knihovny. Při alokaci operátorem new se tedy přirozeně alokuje medvěd s jedinou proměnnou weight. Co však čert nechtěl, implementace metody EatHoney v nové knihovně používá i proměnnou paw. Sáhne tedy do nealokovaného místa v paměti - a to obvykle nedopadne šťastně.
Tento příklad jsem uvedl záměrně podrobně, aby bylo vidět, že ani dynamické knihovny nejsou všespasitelné, pokud nejsou dána pravidla, kterak je používat.