다음을 통해 공유


다른 Office 솔루션의 VSTO 추가 기능에서 코드 호출

VSTO 추가 기능의 개체를 다른 Microsoft Office 솔루션을 비롯한 다른 솔루션에 노출할 수 있습니다. 이는 해당 VSTO 추가 기능이 다른 솔루션에서 사용하도록 하려는 서비스를 제공하는 경우에 유용합니다. 예를 들어 웹 서비스의 재무 데이터에 대해 계산을 수행하는 Microsoft Office Excel용 VSTO 추가 기능이 있는 경우 다른 솔루션에서는 런타임에 이 Excel VSTO 추가 기능을 호출하여 이러한 계산을 수행할 수 있습니다.

적용 대상: 이 항목의 정보는 VSTO 추가 기능 프로젝트에 적용됩니다. 자세한 내용은 Office 애플리케이션 및 프로젝트 형식에 따라 사용 가능한 기능을 참조하세요.

이 프로세스는 크게 다음과 같은 두 가지 단계로 구성되어 있습니다.

  • VSTO 추가 기능에서 개체를 다른 솔루션에 노출합니다.

  • 다른 솔루션에서 VSTO 추가 기능을 통해 노출된 개체에 액세스하고 개체의 멤버를 호출합니다.

추가 기능의 코드를 호출할 수 있는 솔루션의 형식

VSTO 추가 기능의 개체를 노출할 수 있는 솔루션의 형식은 다음과 같습니다.

  • VSTO 추가 기능과 동일한 애플리케이션 프로세스에서 로드되는 문서의 VBA(Visual Basic for Applications) 코드

  • VSTO 추가 기능과 동일한 애플리케이션 프로세스에서 로드되는 문서 수준 사용자 지정

  • Visual Studio의 Office 프로젝트 템플릿을 사용하여 만든 다른 VSTO 추가 기능

  • COM VSTO 추가 기능(즉, IDTExtensibility2 인터페이스를 직접 구현하는 VSTO 추가 기능)

  • VSTO 추가 기능과 다른 프로세스에서 실행되는 솔루션(이러한 유형의 솔루션을 OOP(Out-of-Process) 클라이언트라고도 함). 여기에는 Windows Forms 또는 콘솔 애플리케이션 같은 Office 애플리케이션을 자동화하는 애플리케이션, 그리고 다른 프로세스에서 로드되는 VSTO 추가 기능이 포함됩니다.

다른 솔루션에 개체 노출

VSTO 추가 기능의 개체를 다른 솔루션에 노출하려면 VSTO 추가 기능에서 다음 단계를 수행합니다.

  1. 다른 솔루션에 노출하려는 클래스를 정의합니다.

  2. RequestComAddInAutomationService 클래스에서 ThisAddIn 메서드를 재정의합니다. 다른 솔루션에 노출하려는 클래스의 인스턴스를 반환합니다.

다른 솔루션에 노출하려는 클래스 정의

최소한, 노출하려는 클래스는 public 클래스여야 하며, ComVisibleAttribute 특성이 true로 설정되어 있어야 하고, IDispatch 인터페이스를 노출해야 합니다.

IDispatch 인터페이스를 노출하는 데 권장되는 방식은 다음 단계를 수행하는 것입니다.

  1. 다른 솔루션에 노출하려는 멤버를 선언하는 인터페이스를 정의합니다. 이 인터페이스를 VSTO 추가 기능 프로젝트에 정의할 수 있습니다. 하지만 클래스를 비VBA 솔루션에 노출하려는 경우에는 이 인터페이스를 별도의 클래스 라이브러리 프로젝트에 정의해야 할 수 있습니다. 이렇게 해야 VSTO 추가 기능을 호출하는 솔루션이 VSTO 추가 기능 프로젝트를 참조하지 않고 인터페이스를 참조할 수 있기 때문입니다.

  2. ComVisibleAttribute 특성을 이 인터페이스에 적용하고 이 특성을 true로 설정합니다.

  3. 이 인터페이스에 구현할 클래스를 수정합니다.

  4. ClassInterfaceAttribute 특성을 클래스에 적용하고 이 특성을 ClassInterfaceType 열거형의 없음 값으로 설정합니다.

  5. 클래스를 OOP(Out-of-Process) 클라이언트에 노출하려면 다음을 수행해야 할 수 있습니다.

    • StandardOleMarshalObject에서 클래스를 파생합니다. 자세한 내용은 Out-of-Process 클라이언트에 클래스 노출을 참조하세요.

    • 인터페이스를 정의하는 프로젝트에서 COM Interop 등록 속성을 설정합니다. 이 속성은 클라이언트에서 초기 바인딩을 사용하여 VSTO 추가 기능을 호출하도록 하려는 경우에만 필요합니다.

    다음 코드 예제에서는 다른 솔루션에서 호출할 수 있는 AddInUtilities 메서드와 ImportData 클래스를 보여 줍니다. 더 큰 규모의 연습의 컨텍스트에서 이 코드를 보려면 연습: VBA에서 VSTO 추가 기능의 코드 호출을 참조하세요.

    [ComVisible(true)]
    public interface IAddInUtilities
    {
        void ImportData();
    }
    
    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.None)]
    public class AddInUtilities : IAddInUtilities
    {
        // This method tries to write a string to cell A1 in the active worksheet.
        public void ImportData()
        {
            Excel.Worksheet activeWorksheet = Globals.ThisAddIn.Application.ActiveSheet as Excel.Worksheet;
    
            if (activeWorksheet != null)
            {
                Excel.Range range1 = activeWorksheet.get_Range("A1", System.Type.Missing);
                range1.Value2 = "This is my data";
            }
        }
    }
    

VBA에 클래스 노출

위에 나와 있는 단계를 수행하는 경우 VBA 코드는 인터페이스에서 선언하는 메서드만 호출할 수 있습니다. VBA 코드는 클래스가 Object같은 기본 클래스에서 가져오는 메서드를 비롯해 클래스의 다른 모든 메서드를 호출할 수 없습니다.

또는 ClassInterfaceAttribute 특성을 ClassInterfaceType 열거형의 AutoDispatch 또는 AutoDual 값으로 설정하여 IDispatch 인터페이스를 노출할 수 있습니다. 인터페이스를 노출하면 별도의 인터페이스에서 메서드를 선언할 필요가 없습니다. 하지만 VBA 코드는 Object같은 기본 클래스에서 가져오는 메서드를 포함하여 클래스의 모든 public 및 비정적 메서드를 호출할 수 있습니다. 하지만 초기 바인딩을 사용하는 OOP(Out-of-Process) 클라이언트는 클래스를 호출할 수 없습니다.

Out-of-Process 클라이언트에 클래스 노출

OOP(Out-of-Process) 클라이언트에 VSTO 추가 기능의 클래스를 노출하려면 StandardOleMarshalObject 에서 클래스를 파생시켜 OOP 클라이언트가 노출된 VSTO 추가 기능 개체를 호출할 수 있도록 해야 합니다. 그렇지 않은 상태에서 OOP(Out-of-Process) 클라이언트에서 노출된 개체 인스턴스를 가져오려고 하면 예기치 않게 실패할 수 있습니다.

이 실패는 Office 애플리케이션의 개체 모델에 대한 모든 호출은 주 UI 스레드에서 수행해야 하지만 OOP(Out-of-Process) 클라이언트에서 개체로의 호출은 인위적인 RPC(원격 프로시저 호출) 스레드에 도착하기 때문입니다. .NET Framework의 COM 마샬링 메커니즘은 스레드를 전환하지 않으며 대신 주 UI 스레드 대신 들어오는 RPC 스레드에서 개체에 대한 호출을 마샬링하려고 합니다. 개체가 StandardOleMarshalObject에서 파생되는 클래스의 인스턴스인 경우 개체에 대한 들어오는 호출은 노출된 개체가 만들어진 스레드에 대해 자동으로 마샬링되며, 이 스레드는 호스트 애플리케이션의 주 UI 스레드가 됩니다.

Office 솔루션에서 스레드를 사용하는 방법에 대한 자세한 내용은 Threading Support in Office을 참조하세요.

RequestComAddInAutomationService 메서드 재정의

다음 코드 예제에서는 VSTO 추가 기능의 RequestComAddInAutomationService 클래스에서 ThisAddIn 를 재정의하는 방법을 보여 줍니다. 이 예제에서는 다른 솔루션에 노출하려는 AddInUtilities라는 클래스를 정의했다고 가정합니다. 더 큰 규모의 연습의 컨텍스트에서 이 코드를 보려면 연습: VBA에서 VSTO 추가 기능의 코드 호출을 참조하세요.

private AddInUtilities utilities;

protected override object RequestComAddInAutomationService()
{
    if (utilities == null)
        utilities = new AddInUtilities();

    return utilities;
}

VSTO 추가 기능이 로드되면 Visual Studio Tools for Office 런타임은 RequestComAddInAutomationService 메서드를 호출합니다. 런타임은 반환된 개체를 VSTO 추가 기능을 나타내는 COMAddIn 개체의 COMAddIn.Object 속성에 할당합니다. 이 COMAddIn 개체는 다른 Office 솔루션은 물론, Office를 자동화하는 솔루션에서 사용할 수 있습니다.

다른 솔루션에서 개체에 액세스

VSTO 추가 기능에서 노출된 개체를 호출하려면 클라이언트 솔루션에서 다음을 수행합니다.

  1. 노출된 VSTO 추가 기능을 나타내는 COMAddIn 개체를 가져옵니다. 클라이언트는 호스트 Office 애플리케이션의 개체 모델에서 Application.COMAddIns 속성을 활용하여 사용 가능한 모든 VSTO 추가 기능에 액세스할 수 있습니다.

  2. COMAddIn 개체의 COMAddIn.Object 속성에 액세스합니다. 이 속성은 VSTO 추가 기능에서 노출된 개체를 반환합니다.

  3. 노출된 개체의 멤버를 호출합니다.

    COMAddIn.Object 속성의 반환 값을 사용하는 방법은 VBA 클라이언트와 VBA가 아닌 클라이언트에서 다릅니다. OOP(Out-of-Process) 클라이언트의 경우 가능한 경합 상태가 발생하지 않도록 하기 위해 추가 코드가 필요합니다.

VBA 솔루션에서 개체 액세스

다음 코드 예제에서는 VBA를 사용하여 VSTO 추가 기능을 통해 노출되는 메서드를 호출하는 방법을 보여 줍니다. 이 VBA 매크로는 ImportData ExcelImportData 라는 VSTO 추가 기능에 정의된라는 메서드를 호출합니다. 더 큰 규모의 연습의 컨텍스트에서 이 코드를 보려면 연습: VBA에서 VSTO 추가 기능의 코드 호출을 참조하세요.

Sub CallVSTOMethod()
    Dim addIn As COMAddIn
    Dim automationObject As Object
    Set addIn = Application.COMAddIns("ExcelImportData")
    Set automationObject = addIn.Object
    automationObject.ImportData
End Sub

비VBA 솔루션에서 개체에 액세스

비VBA 솔루션에서는 구현하는 인터페이스로 COMAddIn. 속성 값을 캐스팅해야 하며, 그런 후에 인터페이스 개체에서 노출된 메서드를 호출할 수 있습니다. 다음 코드 예제에서는 Visual Studio에서 Office 개발자 도구를 사용하여 만든 다른 VSTO 추가 기능에서 ImportData 메서드를 호출하는 방법을 보여 줍니다.

object addInName = "ExcelImportData";
Office.COMAddIn addIn = Globals.ThisAddIn.Application.COMAddIns.Item(ref addInName);
ExcelImportData.IAddInUtilities utilities = (ExcelImportData.IAddInUtilities)addIn.Object;
utilities.ImportData();

이 예에서 COMAddIn.Object 속성 값을 IAddInUtilities 인터페이스가 아닌 AddInUtilities 클래스로 캐스팅하려고 하면 코드에서 InvalidCastException이 throw됩니다.