Szoftverfejlesztés .NET platformon - Jegyzet 13. fejezet

A VIK Wikiből

Ez az oldal a korábbi SCH wikiről lett áthozva.

Ha úgy érzed, hogy bármilyen formázási vagy tartalmi probléma van vele, akkor, kérlek, javíts rajta egy rövid szerkesztéssel!

Ha nem tudod, hogyan indulj el, olvasd el a migrálási útmutatót.


70-536 .NET Framework 2.0 Application Development Foundation

%TOC{depth="3"}%

Interop célja:

  • együttműködés legacy (nem .NET) alkalmazásokkal
  • együttműködés az Office termékekkel

A COM komponens importálásához szükséges, hogy

  • a komponens regisztrálva legyen (Regsvr32)
  • importálni kell őket
    • VS-ben Add Reference.../COM fül vagy
    • TlbImp.exe-vel konvertáljuk COM dll-ből .NET assemblyvé (/out kapcsolóval át is nevezhetjük),

aztán Add Reference...

COM és .NET közötti együttműködés

  • odafele: Runtime Callable Wrapper (RCW) segítségével
  • visszafele: COM Callable Wrapper (CCW) segítségével

Gáz az optional paraméterek használatával: csak a VB2005 támogatja őket, a C# nem. Workaround: Type.Missing vagy kerüljük őket.

private static Object optionalParamHandler = Type.Missing;
static void Main(string[] args) {
	 Application newExcelApp = new Application();
	 newExcelApp.Worksheets.Add(optionalParamHandler, optionalParamHandler,
		  optionalParamHandler, optionalParamHandler);
}

COM eszközök

  • Tlbimp.exe
  • Tlbexp.exe
  • Ildasm.exe: Intermediate Language Disassembler
  • Regedit.exe: kézi komponens regisztráció vagy törlés
  • Regasm.exe: .NET assemblyket regisztál / töröl a registryből

Exception kezelés

A .NET-es Exception osztály nem kompatibilis a COM exception-ökkel (a RuntimeWrappedException nem az Exception osztályból származik), ezért az 1.1-ben nem volt elkapható a catch (Exception e)-vel, csak az üres catch boldogult vele. 2.0-ban már elkapható, az eredeti állapotot az =[assembly: RuntimeCompatibility(WrapNonExceptionThrows=false)]= attribútummal lehet visszaállítani.

Egyéb COM hiányosságok

  • nincsenek statikus tagok
  • nincs paraméteres konstruktor
  • a leszármazott osztályban eltakart tagok nem hívhatók
  • registryre épül => Linuxra nem portolható

.NET library exportálása COM libraryként

  • Project Properties / Build / Output / Register For COM Interop
  • Mi legyen látható kívülről:

=[assembly: ComVisible(bool)]= (assembly), =[ComVisible(bool)]= (osztályok, tagok)

  • Szükség van default konstruktorra
  • Az exportálandó típusok, tagváltozók és metódusok legyenek publikusak
  • Az absztrakt osztályok nem exportálhatók

Kézi exportálás (lehet VS-val is)

  • csc /t:library ComDemo.cs
  • tlbexp ComDemo.dll /out:ComDemo.tlb
  • ComDemo.res tartalma legyen 1 sor: IDR_TYPELIB1 typelib "ComDemo.tlb"
  • rc ComDemo.res
  • csc /t:library ComDemo.cs /win32res:ComDemo.res

Nem felügyelt WinAPI hívás: Platform Invoke (P/Invoke) segítségével

  • System.Runtime.InteropServices névtér importálása
  • static extern metódus deklaráció a WinAPI függvény nevén
  • [DllImport] attribútummal ellátva
  • A string argumentumok helyett StringBuildert kell használni
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

Az egyszerű típusok konverziója automatikussá tehető a [MarshalAs] attribútummal

class MarshalAsDemo {
	 [MarshalAs(UnmanagedType.LPStr)]
	 public String FirstName;
	 public String LastName([MarshalAs(UnmanagedType.LPStr)] String firstName) { }
	 [MarshalAs(UnmanagedType.Bool)]
	 public Boolean IsCurrentlyWorking;
}

A struktúrák a [StructLayout] attribútummal konvertálhatók

  • [StructLayout(LayoutKind.Sequential)]: adattagok folytonosan jönnek egymás után
  • [StructLayout(LayoutKind.Explicit)]:

[FieldOffset(offset)] attribútumokkal szabályozható az adattagok helye

  • Marshal.SizeOf-fal kérdezhető le a struktúra mérete

Callback függvények delegate segítségével importálhatók.

public delegate Boolean DemoCallback(IntPtr hWnd, Int32 lParam);
[DllImport("user32.dll")]
public static extern Int32 EnumWindows(DemoCallback callback, Int32 param);
public static Boolean DisplayWindowInfo(IntPtr hWnd, Int32 lParam) { ... }
public static void RunDemo() {
	 EnumWindows(DisplayWindowInfo, 0);
}

Exception kezelés

  • Régen GetLastError hívással
  • .NET-ben nem használható, mert még kiolvasás előtt új értéket kaphat
  • Helyette: ha a [DllImport]-ot SetLastError=true paraméterrel használjuk,

a Marshal.GetLastWin32Error() visszaadja a hibakódot

Natív kód hátrányai

  • overhead a marshaling miatt
  • nem teljesen type safe
  • a .NET-es security nem használható
  • nincs verziókezelés

-- Peti - 2007.07.03.