0Pricing
C# Academy · Lekcja

Interop COM i opakowania wywoływalne ze środowiska uruchomieniowego

Proszę korzystać z komponentów COM w języku C# za pomocą RCW, importować biblioteki typów i obsługiwać wyjątki HRESULT.

Interop COM i opakowania wywoływalne ze środowiska uruchomieniowego to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Czym jest COM Interop?

COM (Component Object Model) to starszy standard binarnego interfejsu firmy Microsoft, nadal używany przez pakiet Office, Windows Shell, starsze interfejsy API DirectX i wiele narzędzi korporacyjnych. .NET może korzystać z komponentów COM za pośrednictwem opakowań interop, które tłumaczą dane między obiektami zarządzanymi a interfejsami COM.

Runtime Callable Wrappers (RCW)

Gdy kod .NET uzyskuje dostęp do obiektu COM, CLR tworzy Runtime Callable Wrapper (RCW) — zarządzany obiekt pośredniczący opakowujący obiekt COM. RCW automatycznie obsługuje zliczanie odwołań (AddRef/Release), wątki apartamentowe oraz marszaling między typami COM i .NET.

// The RCW is created automatically when you instantiate a COM class
// via a registered ProgID or CLSID

// Example: create an Excel Application COM object
Type excelType = Type.GetTypeFromProgID("Excel.Application")!;
object excelApp = Activator.CreateInstance(excelType)!;

// excelApp is an RCW — the CLR wraps the underlying IDispatch COM object
// COM AddRef is called; CLR tracks references
Console.WriteLine(excelApp.GetType().Name); // ApplicationClass

Importowanie bibliotek typów (TLB)

Narzędzie tlbimp.exe (Type Library Importer) odczytuje bibliotekę typów COM (.tlb lub bibliotekę osadzoną w .dll) i generuje zestaw interop .NET z silnie typowanymi klasami RCW oraz definicjami interfejsów.

// From a Developer Command Prompt:
// tlbimp MyComLib.dll /out:MyComLib.Interop.dll

// Or reference via Visual Studio:
// Add Reference → COM → Microsoft Excel 16.0 Object Library
// → Generates Microsoft.Office.Interop.Excel.dll automatically

// The generated Interop assembly contains:
// - Interface types (matching COM vtable layout)
// - Co-class wrappers (implement the interfaces)
// - Enum types (from the type library)
// - Delegate types for COM event sinks

Używanie obiektu COM za pośrednictwem zestawu interop

Po dodaniu odwołania do zestawu interop typy COM wyglądają jak zwykłe typy .NET. Wywołanie metody jest tłumaczone przez RCW na wywołanie za pośrednictwem tablicy vtable COM. Obiekty COM należy zawsze prawidłowo zwalniać, aby uniknąć wycieków zasobów.

using Microsoft.Office.Interop.Excel;

Application excel = new Application();
excel.Visible = false;

Workbooks books = excel.Workbooks;
Workbook wb = books.Add();
Worksheet ws = (Worksheet)wb.Sheets[1];

((Range)ws.Cells[1, 1]).Value = "Hello, COM!";
wb.SaveAs(@"C:\Temp\test.xlsx");
wb.Close();

// Release COM RCW explicitly
Marshal.ReleaseComObject(ws);
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(books);
excel.Quit();
Marshal.ReleaseComObject(excel);

Marshal.ReleaseComObject

COM używa zliczania odwołań — AddRef/Release. RCW wywołuje Release dopiero po zebraniu przez GC, co może nastąpić znacznie później. Wywołaj Marshal.ReleaseComObject(), aby natychmiast zmniejszyć licznik odwołań RCW i zwolnić obiekt COM bez oczekiwania na GC.

// Pattern: release COM objects in finally block
Application? excel = null;
Workbook? wb = null;
try
{
    excel = new Application();
    wb = excel.Workbooks.Add();
    // ... do work ...
}
finally
{
    if (wb   != null) Marshal.ReleaseComObject(wb);
    if (excel != null)
    {
        excel.Quit();
        Marshal.ReleaseComObject(excel);
    }
    // Force GC to clean up any remaining RCWs
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

HRESULT i wyjątki COM

Metody COM zwracają wartości HRESULT sygnalizujące powodzenie lub niepowodzenie. RCW automatycznie sprawdza wartość HRESULT i zgłasza wyjątek COMException (lub bardziej szczegółowy wyjątek), gdy wskazuje ona na niepowodzenie. Obsługuje się je za pomocą zwykłego try/catch.

try
{
    // COM method that might fail
    Workbook wb = excel.Workbooks.Open(@"C:\missing.xlsx");
}
catch (COMException ex) when (ex.HResult == unchecked((int)0x800A03EC))
{
    // Excel-specific HRESULT for file not found
    Console.WriteLine($"Excel error: {ex.Message}");
}
catch (COMException ex)
{
    // General COM failure
    Console.WriteLine($"COM error 0x{ex.HResult:X8}: {ex.Message}");
}

Późne wiązanie za pomocą dynamic

Jeśli nie mają Państwo biblioteki typów ani zestawu interop, można użyć słowa kluczowego dynamic w języku C# do późnego wiązania wywołań COM (IDispatch). Jest to wolniejsze — identyfikatory dyspozycji są rozwiązywane w czasie działania — ale nie wymaga wygenerowanych opakowań.

// Late-bound COM via dynamic — no interop DLL needed
Type type = Type.GetTypeFromProgID("Word.Application")!;
dynamic word = Activator.CreateInstance(type)!;

word.Visible = false;
dynamic docs = word.Documents;
dynamic doc = docs.Add();

doc.Content.Text = "Late-bound COM example";
doc.SaveAs2(@"C:\Temp\test.docx");
doc.Close();
word.Quit();

Marshal.ReleaseComObject(doc);
Marshal.ReleaseComObject(docs);
Marshal.ReleaseComObject(word);

Odbiorniki zdarzeń COM

Obiekty COM zgłaszają zdarzenia za pośrednictwem punktów połączeń. Zestaw interop generuje interfejsy odbiorników zdarzeń. Można subskrybować je za pomocą zwykłych delegatów i zdarzeń .NET, a RCW obsługuje mechanizmy COM IConnectionPoint.

using Microsoft.Office.Interop.Excel;

Application excel = new Application();
excel.Visible = true;

// Subscribe to COM event via generated event wrapper
excel.WorkbookBeforeClose += (wb, ref cancel) =>
{
    Console.WriteLine($"Closing: {wb.Name}");
    // Set cancel = true to prevent close
};

excel.WorkbookOpen += (wb) =>
{
    Console.WriteLine($"Opened: {wb.Name}");
};

// Open a workbook to trigger events
excel.Workbooks.Open(@"C:\Temp\test.xlsx");

Apartamenty COM: STA a MTA

Wiele komponentów COM, szczególnie związanych z interfejsem użytkownika, takich jak Office, wymaga apartamentu jednowątkowego (STA). Wątki tworzące obiekty COM STA należy zawsze oznaczać atrybutem [STAThread] (Main) lub ustawić stan apartamentu wątku przed jego uruchomieniem.

// Console apps default to MTA — COM Office automation requires STA
// Option 1: Mark Main with [STAThread]
[STAThread]
static void Main()
{
    var excel = new Microsoft.Office.Interop.Excel.Application();
    // ...
}

// Option 2: Run on an STA thread manually
Thread staThread = new Thread(() =>
{
    var excel = new Microsoft.Office.Interop.Excel.Application();
    // ...
    excel.Quit();
    Marshal.ReleaseComObject(excel);
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();

ComImport i ręczne deklaracje COM

Interfejsy COM można deklarować ręcznie za pomocą atrybutów [ComImport], [Guid] i [InterfaceType] — jest to przydatne, gdy nie istnieje biblioteka typów lub potrzebny jest tylko podzbiór dużego interfejsu API COM.

[ComImport]
[Guid("00000000-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IUnknown
{
    void QueryInterface(ref Guid riid, out IntPtr ppvObject);
    int  AddRef();
    int  Release();
}

// Declare a specific COM interface you want to consume:
[ComImport]
[Guid("0000010C-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPersist
{
    void GetClassID(out Guid pClassID);
}

Szybkie sprawdzenie

Jaki jest cel Runtime Callable Wrapper (RCW) w mechanizmie COM Interop platformy .NET?

Podsumowanie: COM Interop i Runtime Callable Wrappers

Najważniejsze wnioski:

  • RCW to zarządzany obiekt pośredniczący opakowujący obiekt COM; CLR automatycznie tworzy jeden dla każdego obiektu COM
  • Za pomocą tlbimp.exe lub odwołań w Visual Studio można generować silnie typowane zestawy interop
  • Wywołaj Marshal.ReleaseComObject(), aby natychmiast zwolnić obiekty COM — nie należy czekać na GC
  • Błędy COM są zgłaszane jako COMException z oryginalną wartością HRESULT
  • dynamic umożliwia późne wiązanie wywołań COM bez zestawu interop
  • Komponenty COM pakietu Office i interfejsu użytkownika wymagają wątku STA — należy użyć [STAThread] lub ustawić stan apartamentu

Często zadawane pytania

Czy lekcja „Interop COM i opakowania wywoływalne ze środowiska uruchomieniowego” jest bezpłatna?

Tak — pełny tekst „Interop COM i opakowania wywoływalne ze środowiska uruchomieniowego” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Interop COM i opakowania wywoływalne ze środowiska uruchomieniowego”?

Proszę korzystać z komponentów COM w języku C# za pomocą RCW, importować biblioteki typów i obsługiwać wyjątki HRESULT. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Interop COM i opakowania wywoływalne ze środowiska uruchomieniowego”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy P/Invoke
  2. LibraryImport i generowane P/Invoke
  3. Kod niebezpieczny, wskaźniki i bufory o stałym rozmiarze
  4. Interop COM i opakowania wywoływalne ze środowiska uruchomieniowego
← Powrót do C# Academy