사용자 지정 서로게이트 작성

시스템 제공 서로게이트는 대부분의 상황에서 적합하지만 사용자 지정 서로게이트를 작성하는 것이 가치가 있는 경우도 있습니다. 다음은 몇 가지 예제입니다.

  • 사용자 지정 서로게이트는 시스템 서로게이트에 없는 일부 최적화 또는 의미 체계를 제공할 수 있습니다.
  • In-process DLL에 클라이언트와 동일한 프로세스에 있는 것에 따라 달라지는 코드가 포함된 경우 DLL 서버가 시스템 서로게이트에서 실행되는 경우 DLL 서버가 제대로 작동하지 않습니다. 사용자 지정 서로게이트는 이를 처리하기 위해 특정 DLL에 맞게 조정할 수 있습니다.
  • 시스템 서로게이트는 무료 모델과 아파트 모델 DLL을 모두 로드할 수 있도록 혼합 스레딩 모델을 지원합니다. 사용자 지정 서로게이트는 효율성상의 이유로 아파트 DLL만 로드하거나 로드할 수 있는 DLL 형식에 대한 명령줄 인수를 수락하도록 조정할 수 있습니다.
  • 사용자 지정 서로게이트는 시스템 서로게이트가 수행하지 않는 추가 명령줄 매개 변수를 사용할 수 있습니다.
  • 시스템 서로게이트는 CoInitializeSecurity 를 호출하고 레지스트리의 AppID 키 아래에 있는 기존 보안 설정을 사용하도록 지시합니다. 사용자 지정 서로게이트는 다른 보안 컨텍스트를 사용할 수 있습니다.
  • 원격 사용할 수 없는 인터페이스(예: 최근 OCX의 인터페이스)는 시스템 서로게이트에서 작동하지 않습니다. 사용자 지정 서로게이트는 DLL의 인터페이스를 자체 구현으로 래핑하고 인터페이스를 원격으로 만들 수 있는 원격 IDL 정의와 함께 프록시/스텁 DLL을 사용할 수 있습니다.

기본 서로게이트 스레드는 일반적으로 다음 설정 단계를 수행해야 합니다.

  1. CoInitializeEx를 호출하여 스레드를 초기화하고 스레딩 모델을 설정합니다.
  2. 서버에서 실행할 DLL 서버가 AppID 레지스트리 키의 보안 설정을 사용할 수 있도록 하려면 EOAC_APPID 기능을 사용하여 CoInitializeSecurity 를 호출합니다. 그렇지 않으면 레거시 보안 설정이 사용됩니다.
  3. CoRegisterSurrogate를 호출하여 서로게이트 인터페이스를 COM에 등록합니다.
  4. 요청 된 CLSID에 대해 ISurrogate::LoadDllServer 를 호출합니다.
  5. 루프에 기본 스레드를 배치하여 CoFreeUnusedLibraries를 주기적으로 호출합니다.
  6. COM 에서 ISurrogate::FreeSurrogate를 호출하면 모든 클래스 팩터리를 해지하고 종료합니다.

서로게이트 프로세스는 ISurrogate 인터페이스를 구현해야 합니다. 새 서로게이트가 시작될 때와 CoInitializeEx를 호출한 후에 이 인터페이스를 등록해야 합니다. 이전 단계에서 설명한 대로 ISurrogate 인터페이스에는 COM에서 호출하는 두 가지 메서드인 LoadDllServer가 새 DLL 서버를 기존 서로게이트에 동적으로 로드합니다. 및 FreeSurrogate를 사용하여 서로게이트를 해제합니다.

로드 요청을 사용하여 COM이 호출하는 LoadDllServer 구현은 먼저 IUnknown, IClassFactoryIMarshal을 지원하는 클래스 팩터리 개체를 만든 다음 , CoRegisterClassObject 를 호출하여 요청된 CLSID에 대한 클래스 팩터리로 개체를 등록해야 합니다.

서로게이트 프로세스에 의해 등록된 클래스 팩터리는 DLL 서버에서 구현하는 실제 클래스 팩터리는 아니지만 IClassFactoryIMarshal을 지원하는 서로게이트 프로세스에 의해 구현되는 제네릭 클래스 팩터리입니다. 등록 중인 DLL 서버가 아닌 서로게이트의 클래스 팩터리이므로 서로게이트의 클래스 팩터리는 실제 클래스 팩터리를 사용하여 등록된 CLSID에 대한 개체의 instance 만들어야 합니다. 서로게이트의 IClassFactory::CreateInstance 는 다음 예제와 같이 표시됩니다.

STDMETHODIMP CSurrogateFactory::CreateInstance(
  IUnknown* pUnkOuter, 
  REFIID iid, 
  void** ppv)
{
    void* pcf;
    HRESULT hr;
 
    hr = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, IID_IClassFactory, &pcf);
    if ( FAILED(hr) )
        return hr;
    hr = ((IClassFactory*)pcf)->CreateInstance(pUnkOuter, iid, ppv);
    ((IClassFactory*)pcf)->Release();
    return hr;
}
 

CoGetClassObject를 호출하면 IClassFactory뿐만 아니라 등록된 클래스 팩터리에서 모든 인터페이스를 요청할 수 있으므로 서로게이트의 클래스 팩터리도 IMarshal을 지원해야 합니다. 또한 제네릭 클래스 팩터리는 IUnknownIClassFactory만 지원하므로 다른 인터페이스에 대한 요청은 실제 개체로 전달되어야 합니다. 따라서 다음과 유사해야 하는 MarshalInterface 메서드가 있어야 합니다.

STDMETHODIMP CSurrogateFactory::MarshalInterface(
  IStream *pStm,  
  REFIID riid, void *pv, 
  WORD dwDestContext, 
  void *pvDestContext, 
  DWORD mshlflags )
{   
    void * pCF = NULL;
    HRESULT hr;
 
    hr = CoGetClassObject(clsid, CLSCTX_INPROC_SERVER, NULL, riid, &pCF);
    if ( FAILED(hr) )
        return hr;   
    hr = CoMarshalInterface(pStm, riid, (IUnknown*)pCF, dwDestContext, pvDestContext,  mshlflags);
    ((IUnknown*)pCF)->Release();
    return S_OK;
 

DLL 서버가 있는 서로게이트는 CoRegisterClassObject를 호출하여 DLL 서버의 클래스 개체를 게시해야 합니다. DLL 서로게이트에 대한 모든 클래스 팩터리를 REGCLS_SURROGATE 등록해야 합니다. 서로게이트에 로드된 DLL 서버에는 REGCLS_SINGLUSE 및 REGCLS_MULTIPLEUSE 사용하면 안 됩니다.

필요한 경우 서로게이트 프로세스를 만들기 위한 다음 지침에 따라 적절한 동작을 보장해야 합니다.

DLL 서로게이트