czwartek, 12 lutego 2009

Implementacja klienta OPC w C#

Po wcześniej przytoczonej teorii (COM , DCOM , .NET , Marshalling , .NET i COM) chyba każdy już wie od czego zacząć, by napisać klienta OPC w C#. Niestety nie obędzie się tutaj bez znajomości specyfikacji. Dodatkowo potrzebne będzie spore doświadczenie w korzystaniu z .NET Platform Invocation Services (czyli m.in marshalling'u i umiejętność konwersji definicji wywołań bibliotek kodu niezarządzalnego na definicję języka C#).

Spójrzmy na definicję przykładowej metody AddItems (z interfejsu OPC Item Management: "IOPCItemMgt"):

HRESULT AddItems(
[in] DWORD dwCount,
[in, size_is( dwCount)] OPCITEMDEF * pItemArray,
[out, size_is(,dwCount)] OPCITEMRESULT ** ppAddResults,
[out, size_is(,dwCount)] HRESULT ** ppErrors );

Ta definicja napisana w C# będzie wyglądała następująco:

int AddItems(
[In] int dwCount,
[In] IntPtr pItemArray,
[Out] out IntPtr ppAddResults,
[Out] out IntPtr ppErrors );

Oczywiście postępując w ten sposób i deklarując parametry jako IntPtr, tracimy wiele informacji. Kolejna sprawa, to standardowe mapowanie błędów zwracanych przez obiekt COM (jako HRESULT), które są konwertowane przez mechanizm marszalingu .NET (.NET marshaller) na wyjątek: COMException. Dodatkowo niektóre metody dostępne poprzez COM zwracają kody wyników: zwykle S_OK (ale czasami inne, np. S_FALSE). Z domyślnym mapowaniem, ta informacja może zostać zagubiona. Aby ominąć te problemy można zadeklarować funkcję interfejsu korzystając ze specjalnego atrybutu PreserveSig . Spójrzcie na kod poniżej:

 [ComVisible(true), ComImport,
Guid("39c13a54-011e-11d0-9675-0020afd8adb3"),
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IOPCItemMgt
{
[PreserveSig]
int AddItems(
[In] int dwCount,
[In] IntPtr pItemArray,
[Out] out IntPtr ppAddResults,
[Out] out IntPtr ppErrors );
...

W tej części będzie to już wszystko. Dla tych, którzy chcą rozszerzyć opisane tutaj zagadnienia, polecam artykuł: http://www.codeproject.com/KB/COM/opcdotnet.aspx

4 komentarze:

  1. zezarte z codeproject

    OdpowiedzUsuń
  2. Niniejszy wpis jest częścią większego artykułu: "OPC, DCOM, .NET i C# w jednym stali domu", który powstał na bazie różnych źródeł, jak i mojej wiedzy i doświadczeń.
    W tym wpisie inspirowałem się artykułem "OPC and .NET with COM Interoperability" z Codeproject, czego nie ukrywałem odsyłając na końcu wpisu do wspomnianego artykułu.

    OdpowiedzUsuń
  3. Jestem pod wrażeniem tego jak doskonale przekazujesz swoją wiedzę.

    OdpowiedzUsuń

Posty powiązane / Related posts