poniedziałek, 9 lutego 2009

.NET Platform Invocation Services

Wiele tradycyjnie tworzonych bibliotek (w tym biblioteki wchodzące w skład dostarczanego przez OPC Foundation: "OPC Core Components") stworzone zostały w tradycyjnych językach programowania jak C lub C++ i skompilowane są do kodu maszynowego. Aby wykorzystać stworzoną w ten sposób bibliotekę potrzebne są odpowiednie pliki nagłówkowe (zwykle dostarczone przez producenta biblioteki), które dodawane są do kodu źródłowego tworzonej aplikacji i które powodują wywołanie odpowiednich procedur z biblioteki. Wykorzystanie takich bibliotek w programie napisanym w języku C++ jest dość proste i wystarczy bazować na dołączonych plikach. Inaczej wygląda sprawa wykorzystywania takich biblioteki w zarządzanym kodzie, jakim są programy napisane w języku C#. W takim przypadku nie wystarczy dołączyć odpowiednich plików nagłówkowych (trzeba ew. napisać własne odpowiedniki pewnych plików), ponadto trzeba wykonać pewne dodatkowe zabiegi zapewniające współpracę kodu zarządzanego i niezarządzanego. Problemy te rozwiązuje się przy pomocy .NET Platform Invocation Services, która to usługa pozwala wywoływanie procedur z bibliotek DLL lub komponentów COM (które nie są skompilowane do kodu zarządzanego). Dla każdej wykorzystywanej funkcji z biblioteki należy napisać odpowiednią deklarację. Przykładowo dla funkcji systemu Windows odczytującej wartość licznika procesora, która oryginalnie jest w postaci:

BOOL QueryPerformanceCounter( LARGE_INTEGER *lpPerformanceCount );

napiszemy:

[DllImport("kernel32")] public static extern bool QueryPerformanceCounter(ref Int64 lpPerformanceCount);

Przy pisaniu nowych deklaracji można zauważyć wiele prawidłowości np. *zmienna najczęściej zamieniamy to na IntPtr zmienna (wyjątek stanowi char *zmienna – gdyż to zamieniamy na string lub StringBuilder), **zmienna – zamieniamy na ref IntPtr. Klasa IntPtr służy najczęściej do wskazywania miejsca w niezarządzanym obszarze pamięci. Jeżeli istnieje potrzeba to można zaalokować sobie pamięć w obszarze niezarządzanym, robi się to funkcją Marshal.AllocCoTaskMem(int length) (wykorzystywane jest to np. przy tworzeniu pakietów do wysłania). W zaalokowanym obszarze można pisać i czytać (np. Marshal.WriteByte(pointer, byte)) W przypadku gdyby zaistniał problem przeniesienia struktury lub klasy z obszaru niezarządzanego do zarządzanego, można wykonać to funkcją PtrToStructure(pointer,structure). Ponieważ wykorzystywane tutaj mechanizmy bazują na klasach z przestrzeni nazw: "Marshall", dlatego często do określenia takiego podejścia jest używany termin marszaling (ang. "marshalling").

Brak komentarzy:

Prześlij komentarz

Posty powiązane / Related posts