.NET COM Hell

Možná jste se již také řešili problém s volání COM objektů z .NET aplikace, wizardy a tutorialy vypadají moc pěkně a developer friendly, import COM objektů do referencí projektu klikací metodou je tak snadný, ale brzy každý narazí na problémy spojené se změnou rozhraní COM objektu, novou verzí atd. Před spuštění aplikace/aktivace assembly se provádí kontrola všech referencí a podreferencí projektu, v případě COM interop assembly se provádí kontrola shodné verze COM objektu pro kterou byl wrapper vytvořen – v tom je ale právě ten problém, pokud totiž voláte pouze jednu funkci, která se nemění, s další verzí COM objektu se celá aplikace která danou knihovnu používá nespustí (takže není možné například využívat COM objekty Office pro různé verze), ukončení aplikace není rovněž bezproblémové, protože se nedá nijak snadno zničit všechny reference na COM objekt i když voláte všude možně Marshal.ReleaseComObject (to je konkrétní případ pro Excelu)
Je tedy několik možností jak tento problém řešit:

[more]

  1. pro každou verzi vydávat service pack s novou verzí aplikace 🙁
  2. dynamicky generovat interop assembly a pak jí late bound užíva
  3. využít class RealProxy – Příklad užití je například v projektu SafeCOMWrapper

RealProxy
RealProxy je transparentní proxy kterou je možné řídit volání vzdálených objektů, překládá tak například volání funkcí klienta na specifické volání pro server (v tomto případě COM).

Základní předpokladem je znalost rozhraní serveru, pokud je DCOM server napsán v .NETu, je možné rozhraní vyextrahovat pomocí Reflectoru, v případě že je v C++ nebo jiném nativním jazyce, můžeme nejprve vytvořit interop assembly pomocí referencí ve Visual Studiu nebo příkazem tlbimp.exe a následně inteface přečíst pomocí Reflectoru.
Dostaneme tedy například:

public interface ICallMeCOM : IDisposable
{
    string HelloWorld(string sayThis);
    string HelloMessage { get; set; }
}

Teď zpět k projektu SafeCOMWrapper:
jedná se u ukázkovou implementaci možného využití RealProxy, v tomto referenčním projektu je navíc řešeno několik bugů jako například předávaní typu decimal referencí.
Kompletní tutorial najdete zde:
http://www.codeproject.com/csharp/SafeCOMWrapper.asp?df=100&forumid=195452&exp=0&select=1418263

Pokud do stejného projektu vložíte zdrojové soubory ze zmíněného odkazu, máte skoro vyhráno, nyní stačí jen objekt aktivovat:

ICallMeCOM callMe = (ICallMeCOM)COMWrapper.CreateInstance(Type.GetTypeFromProgID("PROGID-OBJEKTU"), typeof (ICallMeCOM));

Console.Write(callMe.HelloWorld("test"))

To je vše, jednoduché a spolehlivé 🙂