0Pricing
C# Academy · Урок

Взаимодействие с COM и оболочки, вызываемые средой выполнения

Используйте компоненты COM из C# с помощью RCW, импортируйте библиотеки типов и обрабатывайте исключения HRESULT.

«Взаимодействие с COM и оболочки, вызываемые средой выполнения» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Что такое COM Interop

COM (Component Object Model) — это устаревший двоичный стандарт интерфейсов Microsoft, который по-прежнему используется в Office, оболочке Windows, устаревших API DirectX и многих корпоративных инструментах. .NET может работать с COM-компонентами через interop-обёртки, преобразующие управляемые объекты и интерфейсы COM друг в друга.

Вызываемые средой выполнения обёртки (RCW)

Когда вы обращаетесь к объекту COM из .NET, CLR создаёт вызываемую средой выполнения обёртку (RCW) — управляемый прокси, оборачивающий объект COM. RCW автоматически обрабатывает подсчёт ссылок (AddRef/Release), работу потоков в апартаментах и маршалинг между типами COM и .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

Импорт библиотек типов (TLB)

Инструмент tlbimp.exe (импортёр библиотеки типов) читает библиотеку типов COM (.tlb или библиотеку, встроенную в .dll) и создаёт сборку interop для .NET со строго типизированными классами RCW и определениями интерфейсов.

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

Использование объекта COM через сборку interop

После добавления ссылки на сборку interop типы COM выглядят как обычные типы .NET. Вызов метода передаётся через RCW в диспетчеризацию виртуальной таблицы COM. Всегда правильно освобождайте объекты COM, чтобы избежать утечек ресурсов.

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 использует подсчёт ссылок — AddRef/Release. RCW вызывает Release только после сборки объекта сборщиком мусора, что может произойти значительно позже. Вызовите Marshal.ReleaseComObject(), чтобы немедленно уменьшить счётчик ссылок RCW и освободить объект COM, не дожидаясь сборщика мусора.

// 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 и исключения COM

Методы COM возвращают значения HRESULT, сообщающие об успехе или ошибке. RCW автоматически проверяет HRESULT и выбрасывает COMException (или более конкретное исключение), если значение указывает на ошибку. Обрабатывайте их обычной конструкцией 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}");
}

Позднее связывание с dynamic

Если у вас нет библиотеки типов или сборки interop, можно использовать ключевое слово C# dynamic для позднего связывания с COM через IDispatch. Это медленнее: идентификаторы диспетчеризации разрешаются во время выполнения, — но сгенерированные обёртки не требуются.

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

Объекты COM вызывают события через точки подключения. Сборка interop генерирует интерфейсы приёмников событий. Подписывайтесь на них с помощью обычных делегатов и событий .NET, а RCW берёт на себя взаимодействие с 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");

Апартаменты COM: STA и MTA

Многим компонентам COM, особенно связанным с пользовательским интерфейсом, например Office, требуется однопоточный апартамент (STA). Всегда помечайте потоки, создающие STA-объекты COM, атрибутом [STAThread] (Main) или задавайте состояние апартамента потока до его запуска.

// 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 и ручные объявления COM

Интерфейсы COM можно объявлять вручную с помощью атрибутов [ComImport], [Guid] и [InterfaceType]. Это полезно, если библиотеки типов нет или вам нужна только часть большого 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);
}

Быстрая проверка

Для чего нужна вызываемая средой выполнения обёртка (RCW) в COM Interop .NET?

Повторение: COM Interop и вызываемые средой выполнения обёртки

Основные выводы:

  • RCW — управляемый прокси, оборачивающий объект COM; CLR автоматически создаёт его для каждого объекта COM
  • Используйте tlbimp.exe или ссылки VS, чтобы создавать строго типизированные сборки interop
  • Вызывайте Marshal.ReleaseComObject(), чтобы немедленно освободить объекты COM, не дожидаясь сборщика мусора
  • Ошибки COM проявляются как COMException с исходным значением HRESULT
  • dynamic включает позднюю диспетчеризацию COM без сборки interop
  • Для компонентов COM Office и пользовательского интерфейса требуется поток STA — используйте [STAThread] или задайте состояние апартамента

Часто задаваемые вопросы

Урок «Взаимодействие с COM и оболочки, вызываемые средой выполнения» бесплатный?

Да — полный текст урока «Взаимодействие с COM и оболочки, вызываемые средой выполнения» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Взаимодействие с COM и оболочки, вызываемые средой выполнения»?

Используйте компоненты COM из C# с помощью RCW, импортируйте библиотеки типов и обрабатывайте исключения HRESULT. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Взаимодействие с COM и оболочки, вызываемые средой выполнения»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы P/Invoke
  2. LibraryImport и P/Invoke из исходного кода
  3. Небезопасный код, указатели и буферы фиксированного размера
  4. Взаимодействие с COM и оболочки, вызываемые средой выполнения
← Назад к C# Academy