text: /*++
  
  Copyright (c) 1997-1999 Microsoft Corporation
  
  Module Name:
  
      termmgr.cpp
  
  Abstract:
  
      Implementation of DLL Exports.
  
  Author:
      
      Created 05/01/97 Michael Clark.
  
  --*/
  
  #include "stdafx.h"
  #include "resource.h"
  #include "initguid.h"
  #include "termmgr.h"
  #include "dlldatax.h"
  
  #include "Manager.h"
  #include "allterm.h"
  #include "meterf.h"
  #include "medpump.h"
  
  #include <initguid.h>
  #include <uuids.h>
  
  #include <vfwmsgs.h>
  
  #include "FileRecordingTerminal.h"
  #include "FPTerm.h"
  
  #include "PTUtil.h"
  #include "PTReg.h"
  
  //
  // For the ntbuild environment we need to include this file to get the base
  //  class implementations.
  //
  #ifdef _ATL_STATIC_REGISTRY
  #include <statreg.h>
  #include <statreg.cpp>
  #endif
  
  #include <atlimpl.cpp>
  
  #ifdef _MERGE_PROXYSTUB
  extern "C" HINSTANCE hProxyDll;
  #endif
  
  #ifdef DEBUG_HEAPS
  // ZoltanS: for heap debugging
  #include <crtdbg.h>
  #endif // DEBUG_HEAPS
  
  CComModule _Module;
  
  // Must have an entry here for each cocreatable object.
  
  BEGIN_OBJECT_MAP(ObjectMap)
      OBJECT_ENTRY(CLSID_TerminalManager,                CTerminalManager)
      OBJECT_ENTRY(CLSID_VideoWindowTerminal_PRIVATE,    CVideoRenderTerminal)
      OBJECT_ENTRY(CLSID_MediaStreamingTerminal_PRIVATE, CMediaTerminal)
      OBJECT_ENTRY(CLSID_FileRecordingTerminalCOMClass,  CFileRecordingTerminal)
      OBJECT_ENTRY(CLSID_FilePlaybackTerminalCOMClass,   CFPTerminal)
      OBJECT_ENTRY(CLSID_PluggableSuperclassRegistration,CPlugTerminalSuperclass)
      OBJECT_ENTRY(CLSID_PluggableTerminalRegistration,  CPlugTerminal)
  END_OBJECT_MAP()
  
  //
  // PTInfo
  // Structure used to store information about
  // our pluggable temrinals implemented into Termmgr.dll
  
  typedef struct
  {
      UINT            nSuperclassName;        // Superclass Name
      BSTR            bstrSueprclassCLSID;    // Superclass CLSID
      const CLSID*    pClsidTerminalClass;    // Terminal Class (public CLSID)
      const CLSID*    pClsidCOM;              // COM clsid (private CLSID)
      UINT            nTerminalName;          // Terminal name
      UINT            nCompanyName;           // Company name
      UINT            nVersion;               // Terminal version
      DWORD           dwDirections;           // Terminal directions
      DWORD           dwMediaTypes;           // Media types supported
  } PTInfo;
  
  //
  // Global array with pluggable terminals implemented into Termmgr.dll
  //
  
  PTInfo    g_PlugTerminals[] =
  {
  
      #define SUPERCLASS_CLSID_VIDEO_WINDOW L"{714C6F8C-6244-4685-87B3-B91F3F9EADA7}"
  
      {
          // VideoWindowTerminal
          IDS_VIDEO_SUPERCLASS,                   // superclass name
          SUPERCLASS_CLSID_VIDEO_WINDOW,          //L"{714C6F8C-6244-4685-87B3-B91F3F9EADA7}",
          &CLSID_VideoWindowTerm,
          &CLSID_VideoWindowTerminal_PRIVATE,     // com class id of the terminal object
          IDS_VIDEO_WINDOW_TERMINAL_NAME,         // L"VideoWindow Terminal",
          IDS_TERMINAL_COMPANY_NAME_MICROSOFT,    // L"Microsoft",
          IDS_VIDEO_TERMINAL_VERSION,             // L"1.1",
          TMGR_TD_RENDER,
          TAPIMEDIATYPE_VIDEO
      },
  
      
      #define SUPERCLASS_CLSID_MST L"{214F4ACC-AE0B-4464-8405-07029003F8E2}"
  
      {
          // MediaStreaming Terminal
          IDS_STREAMING_SUPERCLASS,
          SUPERCLASS_CLSID_MST,                   //L"{214F4ACC-AE0B-4464-8405-07029003F8E2}",
          &CLSID_MediaStreamTerminal,
          &CLSID_MediaStreamingTerminal_PRIVATE,
          IDS_MEDIA_STREAMING_TERMINAL_NAME,      //L"MediaStreaming Terminal",
          IDS_TERMINAL_COMPANY_NAME_MICROSOFT,    //L"Microsoft",
          IDS_MEDIA_STREAMING_TERMINAL_VERSION,   //L"1.1",
          TMGR_TD_BOTH,
          TAPIMEDIATYPE_AUDIO
      },
  
  
      #define SUPERCLASS_CLSID_FILE L"{B4790031-56DB-4D3E-88C8-6FFAAFA08A91}"
  
      {
          // FileRecording Terminal
          IDS_FILE_SUPERCLASS,
          SUPERCLASS_CLSID_FILE,                  //L"{B4790031-56DB-4d3e-88C8-6FFAAFA08A91}",
          &CLSID_FileRecordingTerminal,
          &CLSID_FileRecordingTerminalCOMClass,
          IDS_FILE_RECORD_TERMINAL_NAME,          //L"FileRecording Terminal",
          IDS_TERMINAL_COMPANY_NAME_MICROSOFT,    //L"Microsoft",
          IDS_FILE_RECORD_TERMINAL_VERSION,       //L"1.1",
          TMGR_TD_RENDER,
          TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_MULTITRACK
      },
  
  
      {
          // FilePlayback Terminal
          IDS_FILE_SUPERCLASS,
          SUPERCLASS_CLSID_FILE,                  //L"{B4790031-56DB-4d3e-88C8-6FFAAFA08A91}",
          &CLSID_FilePlaybackTerminal,
          &CLSID_FilePlaybackTerminalCOMClass,
          IDS_FILE_PLAYBACK_TERMINAL_NAME,        //L"FilePlayback Terminal",
          IDS_TERMINAL_COMPANY_NAME_MICROSOFT,    //L"Microsoft",
          IDS_FILE_PLAYBACK_TERMINAL_VERSION,     //L"1.1",
          TMGR_TD_CAPTURE,
          TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_MULTITRACK
      }
  
  };
  
  /*++
  PTRegisterTerminal
  
  Is called by PTRegister,
  read the information from the global Pluggable terminals array
  --*/
  HRESULT PTRegisterTerminal(
      IN int                nTerminal
      )
  {
      CPTSuperclass    Superclass;
  
  
      LOG((MSP_TRACE, "PTRegisterTerminal - enter"));
  
      
      //
      // Get the superclass name
      //
  
      Superclass.m_bstrName = SafeLoadString(g_PlugTerminals[nTerminal].nSuperclassName);
  
      if( Superclass.m_bstrName == NULL )
      {
          return E_OUTOFMEMORY;
      }
  
  
      LOG((MSP_TRACE, "PTRegisterTerminal - superclass [%S]", Superclass.m_bstrName));
  
      //
      // Get the superclass CLSID
      //
      HRESULT hr = CLSIDFromString(
          g_PlugTerminals[nTerminal].bstrSueprclassCLSID,
          &Superclass.m_clsidSuperclass);
      if( FAILED(hr) )
      {
          return hr;
      }
  
      Superclass.Add();
  
      CPTTerminal Terminal;
      PTInfo& TermInfo = g_PlugTerminals[nTerminal];
  
      //
      // Get the TerminalClass clsid
      //
  
      Terminal.m_clsidTerminalClass = *TermInfo.pClsidTerminalClass;
  
      //
      // Get terminal's com class id
      //
  
      Terminal.m_clsidCOM = *TermInfo.pClsidCOM;
  
      //
      // Set the other terminal fileds
      // CPTTerminal will deallocate the memory
      //
  
  
      Terminal.m_bstrName = SafeLoadString( TermInfo.nTerminalName );
      if( Terminal.m_bstrName == NULL)
      {
          return E_OUTOFMEMORY;
      }
      
      LOG((MSP_TRACE, "PTRegisterTerminal - terminal [%S]", Terminal.m_bstrName));
  
  
      Terminal.m_bstrCompany = SafeLoadString( TermInfo.nCompanyName );
      if( Terminal.m_bstrCompany == NULL )
      {
          return E_OUTOFMEMORY;
      }
  
      Terminal.m_bstrVersion = SafeLoadString( TermInfo.nVersion );
      if( Terminal.m_bstrVersion == NULL )
      {
          return E_OUTOFMEMORY;
      }
  
      Terminal.m_dwDirections = TermInfo.dwDirections;
      Terminal.m_dwMediaTypes = TermInfo.dwMediaTypes;
  
      //
      // Register terminal
      //
  
      hr = Terminal.Add( Superclass.m_clsidSuperclass );
  
      return hr;
  }
  
  /*++
  PTUnregisterTerminal
  
    Is called by PTUnregister,
    Read the information from global pluggable terminals array
  --*/
  HRESULT PTUnregisterTerminal(
      IN    int                nTerminal
      )
  {
      CPTSuperclass    Superclass;
  
      {
          //
          // Get the superclass name
          //
          TCHAR szName[MAX_PATH+1];
          int nRetVal = LoadString( _Module.GetResourceInstance(), 
              g_PlugTerminals[nTerminal].nSuperclassName,
              szName,
              MAX_PATH
              );
          if( 0 == nRetVal )
          {
              return E_OUTOFMEMORY;
          }
  
          Superclass.m_bstrName = SysAllocString( szName );
      }
  
      //
      // Get the superclass CLSID
      //
      HRESULT hr = CLSIDFromString(
          g_PlugTerminals[nTerminal].bstrSueprclassCLSID,
          &Superclass.m_clsidSuperclass);
  
      //
      // Unregister a terminal
      //
  
      CPTTerminal Terminal;
      Terminal.m_clsidTerminalClass = *g_PlugTerminals[nTerminal].pClsidTerminalClass;
      Terminal.Delete( Superclass.m_clsidSuperclass );
  
      return S_OK;
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // PTRegister
  
  HRESULT PTRegister()
  {
      //
      // Register each pluggable terminal
      //
  
      for(int nItem = 0; 
          nItem < (sizeof( g_PlugTerminals) / sizeof(PTInfo));
          nItem++)
      {
              PTRegisterTerminal( 
                  nItem
                  );
      }
  
     return S_OK;
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // PTUnregister
  HRESULT PTUnregister()
  {
      // Unregister each pluggable terminal
      for(int nItem = 0; 
          nItem < (sizeof( g_PlugTerminals) / sizeof(PTInfo));
          nItem++)
      {
              PTUnregisterTerminal( 
                  nItem
                  );
      }
  
      return S_OK;
  }
  
  
  /////////////////////////////////////////////////////////////////////////////
  // DLL Entry Point
  
  extern "C"
  BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  {
      lpReserved;
  
  #ifdef _MERGE_PROXYSTUB
      if (!PrxDllMain(hInstance, dwReason, lpReserved))
      {
          return FALSE;
      }
  #endif
  
      if (dwReason == DLL_PROCESS_ATTACH)
      {
  
  #ifdef DEBUG_HEAPS
          // ZoltanS: turn on leak detection on process exit
          _CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF );
  
          // ZoltanS: force a memory leak
          char * leak = new char [ 1977 ];
          sprintf(leak, "termmgr.dll NORMAL leak");
          leak = NULL;
  #endif // DEBUG_HEAPS
          
          _Module.Init(ObjectMap, hInstance);
          DisableThreadLibraryCalls(hInstance);
  
          // Register for trace output.
          MSPLOGREGISTER(_T("termmgr"));
      }
      else if (dwReason == DLL_PROCESS_DETACH)
      {
  
          //
          // do not deregister if the process is terminating -- working around 
          // bugs in rtutils that could cause a "deadlock" if DeregisterTracing
          // is called from DllMain on process termination
          //
  
          if (NULL == lpReserved)
          {
              // Deregister for trace output.
  
              MSPLOGDEREGISTER();
          }
  
          _Module.Term();
      }
  
      return TRUE;    // ok
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // Used to determine whether the DLL can be unloaded by OLE
  
  STDAPI DllCanUnloadNow(void)
  {
  #ifdef _MERGE_PROXYSTUB
      if ( PrxDllCanUnloadNow() != S_OK )
      {
          return S_FALSE;
      }
  #endif
  
      if ( _Module.GetLockCount() == 0 )
      {
          //
          // All references to COM objects in this DLL have been released, so
          // the DLL can now be safely unloaded. After this returns, DllMain
          // will be called with dwReason == DLL_PROCESS_DETACH.
          //
  
          return S_OK;
      }
      else
      {
          return S_FALSE;
      }
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // Returns a class factory to create an object of the requested type
  
  STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
  {
  #ifdef _MERGE_PROXYSTUB
      if ( PrxDllGetClassObject(rclsid, riid, ppv) == S_OK )
      {
          return S_OK;
      }
  #endif
  
      return _Module.GetClassObject(rclsid, riid, ppv);
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // DllRegisterServer - Adds entries to the system registry
  
  STDAPI DllRegisterServer(void)
  {
      //
      // Register terminals
      HRESULT hReg = PTRegister();
  
  #ifdef _MERGE_PROXYSTUB
      HRESULT hRes = PrxDllRegisterServer();
  
      if ( FAILED(hRes) )
      {
          return hRes;
      }
  #endif
  
      // registers object, typelib and all interfaces in typelib
      HRESULT hr = _Module.RegisterServer(TRUE);
  
      if( FAILED(hr) )
      {
          //
          // This is real bad
          //
  
          return hr;
      }
  
      if( FAILED(hReg) )
      {
          //
          // Something was wrong with the
          // registration of pluggable terminals
          // 
  
          return hReg;
      }
  
      //
      // Everything was OK
      //
  
      return S_OK;
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // DllUnregisterServer - Removes entries from the system registry
  
  STDAPI DllUnregisterServer(void)
  {
      //
      // Unregister terminals
      //
      PTUnregister();
  
  #ifdef _MERGE_PROXYSTUB
      PrxDllUnregisterServer();
  #endif
  
      _Module.UnregisterServer();
      
      return S_OK;
  }
  
  
  