.NET COM+ 를 Managed/Native 클라이언트에서 각각 호출했을 때의 콜 스택 비교
우선, 테스트 환경을 구성해 볼까요? ^^
C#으로 서버 유형의 COM+ 코드를 다음과 같이 만들어 줍니다.
[GuidAttribute("0C0445BE-A12E-4DE4-A022-156EF491989D")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class MyClass : System.EnterpriseServices.ServicedComponent
{
public object DoIt()
{
System.Diagnostics.Trace.WriteLine(Environment.StackTrace);
return "test";
}
}
[assembly: ApplicationAccessControl(false)]
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationName("TestRDS")]
[assembly: ApplicationID("727FC170-1D80-4e89-84CC-22AAB10A6F24")]
[assembly: ComVisible(true)]
그리고, C# 으로 해당 COM+ 를 호출하는 코드를 (관리자 권한으로) 불러주면,
class Program
{
static void Main(string[] args)
{
TestCOMObj.MyClass mc = new TestCOMObj.MyClass();
Console.WriteLine(mc.DoIt());
}
}
COM+ 구성요소 서비스에 새롭게 COM+ 응용 프로그램이 생성된 것을 볼 수 있습니다.
자, 이제 Visual Studio 의 "Attach to process..." 기능을 이용해서 실행 중인 COM+ exe 개체에 디버거를 연결한 후, DoIt 메서드에 중단점을 잡고 C# 클라이언트를 다시 호출해 주면 다음과 같은 콜 스택이 확인됩니다.
TestCOMObj.dll!TestCOMObj.MyClass.DoIt() Line 18 C#
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(...[생략]...) + 0x1b bytes
mscorlib.dll!System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(...[생략]...) + 0x26a bytes
mscorlib.dll!System.Runtime.Remoting.RemotingServices.ExecuteMessage(...[생략]...) + 0x63 bytes
System.EnterpriseServices.dll!System.EnterpriseServices.ServicedComponentProxy.LocalInvoke(...[생략]...) + 0x1b3 bytes
System.EnterpriseServices.dll!System.EnterpriseServices.ServicedComponentProxy.Invoke(...[생략]...) + 0x55 bytes
System.EnterpriseServices.dll!System.EnterpriseServices.ServicedComponent.RemoteDispatchHelper(...[생략]...) + 0x38 bytes
System.EnterpriseServices.dll!System.EnterpriseServices.ServicedComponent.System.EnterpriseServices.IRemoteDispatch.RemoteDispatchNotAutoDone(string s) + 0x14 bytes
[Native to Managed Transition]
다음으로, C/C++ 클라이언트를 만들고,
#include "stdafx.h"
#import "..\\..\\ConsoleApplication1\\ConsoleApplication1\\bin\\Debug\\TestCOMObj.tlb" no_namespace raw_interfaces_only
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
{
_MyClassPtr ptr;
ptr.CreateInstance(__uuidof(MyClass));
VARIANT vtResult;
ptr->DoIt(&vtResult);
}
CoUninitialize();
return 0;
}
이제 호출을 해보면, C# COM+ 측의 콜스택이 어떻게 나올까요? 제 경우에는, 별반 다르지 않게 콜 스택이 나올 거라고 생각했는데, 그게 아니었습니다.
보시는 것처럼, System.EnterpriseServices, System.Runtime.Remoting.Messaging 클래스가 전혀 관여하지 않고 Native 클라이언트로부터 온 호출이 직접 전달되고 있습니다.
즉, .NET COM+ 개체 자체의 GC 등으로 인한 영향을 제외한다면 Native 클라이언트로부터 .NET COM+ 개체를 호출하는 경우 오버헤드가 전혀 없음을 알 수 있습니다.
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]