Development z Zapomnianej Strony

..:: Paweł Hofman .NET Portal ::..

TytanNET jest moim autorskim dodatkiem (add-in) do Visual Studio 2005 oraz 2008. Głównym celem, jaki mi przyświecał przy jego tworzeniu, było ułatwienie pracy i zmniejszenie nudnego kodowania poprzez automatyzację najczęściej wykonywanych akcji. Zalicza się do nich elementy rozszerzające standardowe środowisko IDE o:

 

Ostatnią wersję możesz pobrać tutaj.



Niestety czasami okazuje się, że platforma .NET nie dostarcza funkcjonalności, które łatwo osiągało się, korzystając po prostu z natywnego Win32 API w C/C++. Przykładem tutaj są chociażby zaawansowane operacje na kontrolkach systemowych, haki w systemie (SetWindowsHookEx), zarządzanie systemowymi ustawieniami (głośność, wyciszenie). Albo wręcz przeciwnie - jesteśmy już w posiadaniu gotowego i działającego komponentu, któremu jedyne, co można zarzucić to fakt, iż został napisany właśnie w C/C++.

Rozwiązania są dwa (proponowane i wspierane przez Microsoft):

  1. Zacząć naukę programowania w Managed C++, który będzie stanowił pomost i korzystał z metod i klas w C++, a wystawiał interfejs dla .NET-owych modułów (assemblies),
  2. skorzystać z mechanizmu Platform Invoke (w skrócie P/Invoke).

 

Za *NIE* używaniem opcji (1) przemawia sama złożoność i komplikacje wprowadzane przez ten mieszany język programowania. Ponadto dochodzi również fakt, iż użyta w nim technika IJW (It-Just-Works) nie działa na urządzeniach mobilnych (np. na żadnym PDA z zainstalowanym Windows Mobile 2003 lub nowszym). Większość kodu odpowiedzialnego za przenoszenie danych (zwykłe kopiowanie z jednego typu struktur na drugi) spada na barki programisty. I zapewne jeszcze dużo, dużo więcej...

 

P/Invoke z kolei gwarantuje bardzo proste przekazywanie całych struktur C# do C/C++ (i w drugą stronę) z użyciem zaimportowanych funkcji (słowo kluczowe extern). Począwszy od .NET 2.0 (oraz CompactFramework 2.0) wszystko to osiągną się programując w C#, eliminując potrzebę posiadania dodatkowego projektu (modułu) pośredniczącego.

Dane są automatycznie kopiowane, bazując na kilku zdefiniowanych odgórnie przez Microsoft:

 

Wokól techniki tej zgromadzona jest też społeczność, która większość, jeśli nie wszystkie wywołania systemowe, zebrała i udostępnia pod adresem: pinvoke.net.



Sposób wywoływania funkcji w programach pisanych w C/C++, Pascalu, assemblerze (rozumianych szeroko jako języki i kod niezarządzany) odgrywa niebagatelne znaczenie. Aby dwie funkcje - wywołująca i wywoływana - mogły się ze sobą dogadać, muszą wcześniej uzgodnić kilka drobnych acz istotnych szczegółów. Należą do nich:

  • sposób, w jaki przekazywane będą argumenty (np. poprzez stos, rejestry lub mieszając oba)
  • sposób, w jaki argumenty są numerowane (od prawej, czy od lewej strony)
  • sposób udekorowania nazwy funkcji (poprzez dodanie przyrostków, przedrostków lub całkowite wygenerowanie nowej nazwy, gwarantujące unikatowość, gdy funkcja jest wielkorotnie przeładowana)
  • czy występuje stała, czy zmienna liczba argumentów (a tym samym, która ze stron będzie odpowiedzialna za posprzątanie)
  • czy występuje wywołanie funkcji globalnej (statycznej) lub metody klasy (C++).

Mimo iż kombinacji wymienionych czynników jest sporo, stosuje się głównie 3 konwencje: fastcall, stdcall, thiscall, cdecl.
Poniżej krótkie omówienie, ze wskazaniem najważniejszych cech oraz zastosowania.

 

Konwencja stdcall (__stdcall)

  • argumenty odkładane na stosie od prawej do lewej (od końca)
  • funkcja wywoływana odpowiedzialna jest za usunięcie argumentów ze stosu (jako, że ich rozmiar jest znany)
  • nazwa funkcji zostaje udekorowana  - otrzymuje znak podkreślenia jako przedrostek  a na końcu po znaku małpy, rozmiar argumentów w bajtach (np. void fun(int arg) -> _fun@4)
  • konwencja ta nadaje się wszędzie tam, gdzie występuje znana liczba argumentów oraz występują restrykcje co do rozmiaru kodu binarnego (który mniejszy jest, gdyż to funkcja wywoływana sprząta stos)

 

Konwencja cdecl (__cdecl)

  • argumenty odkładane na stosie również od prawej do lewej (od końca)
  • funkcja wywołująca odpowiedzialna jest za usunięcie argumentów ze stosu (bo zna ich rozmiar), a to pozwala na stosowanie zmiennej liczby argumetów (np.: printf)
  • nazwa funkcji zostaje poprzedzona podkreślnikiem (np. void fun(int arg) -> _fun)
  • generuje dłuższy kod binarny od stdcall (jako, że sprzątanie stosu jest wstawiane po każdym wywołaniu), ale pozwala na wywołania funkcji ze zmienną listą argumentów

Ciekawe porównanie znaleźć można na codeguru.com.

 

Konwencja fastcall (__fastcall)

  • główną zaletą jest fakt, iż argumenty przekazywane są nie przez stos, a rejestry
  • niemniej jednak wymaga to pewnych założeń
    • rejestry te muszą być w chwili wywołania nieużywane (inaczej ich stan będzie odłożony na stos i zyski z takiego przekazywania argumentów zmaleją)
    • używane są tylko niektóre rejestry (i jeśli funcja ma za dużo argumentów lub ich rozmiar jest za dużo, to i tak będą przekazywane przez stos)
    • kolejność użycia rejestrów zależy wyłącznie od użytego kompilatora (i niektóre pozwalają na własne zdefiniowanie tej kolejności)
    • np. Microsoft C++ Compiler używa ECX i EDX, w których umieszcza dwa pierwsze argumenty (bez upakowania jeśli nie są 32-bitowe), a pozostałe odkłada na stos w kolejności od prawej do lewej (od końca)
  • nazwa funkcji jest poprzedzona znakiem małpy i tak samo jak przy stdcall, na końcu dodany jest również znak małpy oraz rozmiar argumentów w bajtach (np. void fun(int a) -> @fun@4).

 

Konwencja thiscall

  • jest to konwencja stosowana najczęściej przy wywołaniu funkcji danej klasy (w C++)
  • w funkcjach takich zawsze jako pierwszy parametr występuje niejawnie wskaźnik na obiekt klasy (this) wywołujący zadaną metodę
  • funkcja o stałej liczbie argumentów:
    • sama jest odpowiedzialna za posprzątanie stosu
    • przy Microsoft C++ Compiler, wskaźnik na obiekt klasy (this) jest przekazywany przez rejestr ECX
  • funkcja o zmiennej liczbie argumentów:
    • to wywołujący jest odpowiedzialny za posprzątanie stosu
    • w tym miejscu zachowuje się dokładnie jak cdecl - wszystkie argumenty są odkładane i przekazywane przez stos, razem ze wskaźnikiem na obiekt klasy (this)
  • nazwy funkcji nie są zmieniane


Przy tworzeniu własnej witryny niezbędnym może okazać się posiadanie odpowiednich zasobów wizualnych. Jeśli nie jesteśmy zawodowymi grafikami, czasem lepiej posiłkować się dostępnymi w sieci darmowymi (głównie rozpowszechnianymi na bazie licencji Creative Commons) zbiorami ikonek:

Inne katalogi:



Autor

Paweł Hofman [CodeTitans]

ASP.NET
C/C++, C#, Objective-C
SQL

License and Disclaimer

Moje Gry i Aplikacje

Zobacz mnie na GoldenLine

Zobacz mnie na LinkedIn
Supported by Polish SQL Server User Group (PLSSUG)

Supported by WrocNet.org

Zine.net.pl

Wpisy

Projekty

Moje projekty open-source:

Sign in