C# Academy · leksjon

COM-interoperabilitet og runtime-kallbare wrappers

Bruk COM-komponenter fra C# med RCW, importer typebiblioteker og håndter HRESULT-unntak.

Leksjon 4 av 412 trinn

COM-interoperabilitet og runtime-kallbare wrappers er en gratis leksjon i C# Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i C# Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i C# Academy inneholder totalt 4 leksjoner.

Hva er COM-interop?

COM (Component Object Model) er Microsofts eldre standard for binærgrensesnitt, som fortsatt brukes av Office, Windows Shell, eldre DirectX-API-er og mange verktøy i virksomheter. .NET kan bruke COM-komponenter via interop-wrapperer som oversetter mellom managed-objekter og COM-grensesnitt.

Runtime Callable Wrappers (RCW)

Når et COM-objekt aksesseres fra .NET, oppretter CLR-en en Runtime Callable Wrapper (RCW) – en managed proxy som omslutter COM-objektet. RCW-en håndterer referansetelling (AddRef/Release), apartment-tråding og marshalling mellom COM- og .NET-typer automatisk.

// 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

Importere typbiblioteker (TLB)

Verktøyet tlbimp.exe (Type Library Importer) leser et COM-typbibliotek (.tlb eller innebygd i .dll) og genererer en .NET-interop-assembly med sterkt typede RCW-klasser og grensesnittdefinisjoner.

// 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

Bruke et COM-objekt via en interop-assembly

Når interop-assemblyen er referert, ser COM-typer ut som vanlige .NET-typer. Et metodekall oversettes via RCW-en til en COM-vtable-dispatch. Frigi alltid COM-objekter riktig for å unngå ressurslekkasjer.

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 bruker referansetelling – AddRef/Release. RCW-en kaller Release først når den samles inn av GC-en, noe som kan skje mye senere. Kall Marshal.ReleaseComObject() for å redusere RCW-referansetellingen umiddelbart og frigi COM-objektet uten å vente på 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 og COM-unntak

COM-metoder returnerer HRESULT-verdier for å signalisere om operasjonen var vellykket eller mislyktes. RCW-en kontrollerer automatisk HRESULT-verdien og kaster et COMException (eller et mer spesifikt unntak) når den angir feil. Slike unntak håndteres med vanlig 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}");
}

Sen binding med dynamic

Hvis det ikke finnes et typbibliotek eller en interop-assembly, kan C#-nøkkelordet dynamic brukes for senbundet COM-dispatch (IDispatch). Dette er tregere – dispatch-ID-er slås opp under kjøring – men krever ingen genererte wrapper-klasser.

// 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);

COM-hendelsesmottakere

COM-objekter utløser hendelser via connection points. Interop-assemblyen genererer grensesnitt for event sinks. Abonner ved hjelp av vanlige .NET-delegater og -hendelser, så håndterer RCW-en koblingen til COM IConnectionPoint automatisk.

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");

COM-apartments: STA vs MTA

Mange COM-komponenter (særlig brukergrensesnittrelaterte som Office) krever en Single-Threaded Apartment (STA). Merk alltid tråder som oppretter STA-COM-objekter med [STAThread] (Main), eller angi trådens apartment-tilstand før tråden startes.

// 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 og manuelle COM-deklarasjoner

COM-grensesnitt kan deklareres manuelt ved hjelp av [ComImport], [Guid] og [InterfaceType]-attributter – nyttig når det ikke finnes noe typbibliotek, eller når bare en delmengde av et stort COM-API trengs.

[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);
}

Hurtigsjekk

Hva er formålet med en Runtime Callable Wrapper (RCW) i .NET COM-interop?

Oppsummering: COM-interop og Runtime Callable Wrappers

Viktigste punkter:

  • RCW = managed proxy som omslutter et COM-objekt; CLR-en oppretter automatisk én per COM-objekt
  • Bruk tlbimp.exe eller VS References for å generere sterkt typede interop-assemblyer
  • Kall Marshal.ReleaseComObject() for å frigi COM-objekter umiddelbart (ikke vent på GC)
  • COM-feil vises som COMException med den opprinnelige HRESULT-verdien
  • dynamic muliggjør senbundet COM-dispatch uten en interop-assembly
  • Office-/UI-COM-komponenter krever en STA-tråd – bruk [STAThread] eller angi apartment-tilstanden
Gratis å komme i gang

Lær deg C# med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
93
Leksjoner
346

Ofte stilte spørsmål

Er leksjonen «COM-interoperabilitet og runtime-kallbare wrappers» gratis?

Ja – hele teksten i «COM-interoperabilitet og runtime-kallbare wrappers» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av C# Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i C# Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «COM-interoperabilitet og runtime-kallbare wrappers»?

Bruk COM-komponenter fra C# med RCW, importer typebiblioteker og håndter HRESULT-unntak. Du øver på C# Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med C# Academy?

Ingen tidligere erfaring er nødvendig. C# Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «COM-interoperabilitet og runtime-kallbare wrappers»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne C# Academy-leksjonen?

Ja. Alle C# Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Grunnleggende om P/Invoke
  2. LibraryImport og kildegenerert P/Invoke
  3. Usikker kode, pekere og buffere med fast størrelse
  4. COM-interoperabilitet og runtime-kallbare wrappers
← Tilbake til C# Academy