text: //-------------------------------------------------------------------
  //
  // FILE: LicCpa.cpp
  //
  // Summary;
  //      This file contians the DLL & CPL entry points, F1 Help message
  //      hooking, and misc common dialog functions.
  //
  // Entry Points;
  //      CPlSetup
  //      CPlApplet
  //      DllMain
  //
  // History;
  //      Nov-30-94   MikeMi  Created
  //      Mar-14-95   MikeMi  Added F1 Message Filter and PWM_HELP message
  //      Apr-26-95   MikeMi  Added Computer name and remoting
  //      Dec-12-95  JeffParh Added secure certificate support
  //
  //-------------------------------------------------------------------
  
  #include <windows.h>
  #include <cpl.h>
  #include "resource.h"
  #include <stdlib.h>
  #include <stdio.h>
  #include "PriDlgs.hpp"
  #include "SecDlgs.hpp"
  #include "liccpa.hpp"
  #include "Special.hpp"
  
  #include <strsafe.h>
  
  extern "C"
  {
      BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved);
      BOOL APIENTRY CPlSetup( DWORD nArgs, LPSTR apszArgs[], LPSTR *ppszResult );
      LONG CALLBACK CPlApplet( HWND hwndCPL, UINT uMsg, LPARAM lParam1, LPARAM lParam2);
      LRESULT CALLBACK msgprocHelpFilter( int nCode, WPARAM wParam, LPARAM lParam );
  }
  
  // Setup routines
  //
  const CHAR szSETUP_NORMAL[]         = "FULLSETUP";
  const CHAR szSETUP_PERSEAT[]        = "PERSEAT";
  const CHAR szSETUP_UNATTENDED[]     = "UNATTENDED";
  const CHAR szSETUP_NORMALNOEXIT[]   = "FULLSETUPNOEXIT";
  
  const CHAR szREMOTESETUP_NORMAL[]       = "REMOTEFULLSETUP";
  const CHAR szREMOTESETUP_PERSEAT[]      = "REMOTEPERSEAT";
  const CHAR szREMOTESETUP_UNATTENDED[]   = "REMOTEUNATTENDED";
  const CHAR szREMOTESETUP_NORMALNOEXIT[] = "REMOTEFULLSETUPNOEXIT";
  
  // Modes for unattended setup
  //
  const CHAR szUNATTENDED_PERSEAT[]   = "PERSEAT";
  const CHAR szUNATTENDED_PERSERVER[] = "PERSERVER";
  
  // Certificate required / not required
  const CHAR szSETUP_CERTREQUIRED[]    = "CERTREQUIRED";
  const CHAR szSETUP_CERTNOTREQUIRED[] = "CERTNOTREQUIRED";
  
  // Use default help file
  const CHAR szSETUP_DEFAULTHELP[]     = "DEFAULTHELP";
  
  // Setup Error return strings
  //
  static CHAR szSETUP_EXIT[]           = "EXIT";
  static CHAR szSETUP_ERROR[]          = "ERROR";
  static CHAR szSETUP_SECURITY[]       = "SECURITY";
  static CHAR szSETUP_NOREMOTE[]       = "NOREMOTE";
  static CHAR szSETUP_DOWNLEVEL[]      = "DOWNLEVEL";
  
  static CHAR szSETUP_OK[]             = "OK";
  
  
  // Registered help message for F1 hooking
  //
  const WCHAR szF1HELPMESSAGE[] = L"LicCpaF1Help";
  
  HINSTANCE g_hinst = NULL;  // global hinstance of this dll
  HHOOK g_hhook = NULL;      // global hhook for F1 message filter
  UINT PWM_HELP = 0;          // global help message when F1 is pressed
  
  //-------------------------------------------------------------------
  //
  //  Function: msgprocHelpFilter
  //
  //  Summary;
  //      This functions will filter the messages looking for F1, then send
  //      the registered message to the top most parent of that window
  //      informing it that F1 for help was pressed.
  //
  //  Arguments;
  //      (see Win32 MessageProc)
  //
  //  History;
  //      Mar-13-95   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  LRESULT CALLBACK msgprocHelpFilter( int nCode, WPARAM wParam, LPARAM lParam )
  {
      LRESULT lrt = 0;
      PMSG pmsg = (PMSG)lParam;
  
      if (nCode < 0)
      {
          lrt = CallNextHookEx( g_hhook, nCode, wParam, lParam );
      }
      else
      {
          if (MSGF_DIALOGBOX == nCode)
          {
              // handle F1 key
              if ( (WM_KEYDOWN == pmsg->message) &&
                   (VK_F1 == (INT_PTR)pmsg->wParam) )
              {
                  HWND hwnd = pmsg->hwnd;
  
                  // post message to parent that handles help
                  while( GetWindowLong( hwnd, GWL_STYLE ) & WS_CHILD )
                  {
                      hwnd = GetParent( hwnd );
                  }
                  PostMessage( hwnd, PWM_HELP, 0, 0 );
  
                  lrt = 1;
              }
          }
      }
  
      return( lrt );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: InstallF1Hook
  //
  //  Summary;
  //      This will ready the message filter for handling F1.
  //      It install the message hook and registers a message that will
  //      be posted to the dialogs.
  //
  //  Arguments;
  //      hinst [in] - the module handle of this DLL (needed to install hook)
  //      dwThreadId [in] - thread to attach filter to
  //
  //  Notes:
  //      The control.exe does this work and sends the "ShellHelp" message.
  //      A seperate F1 message filter is needed because these dialogs maybe
  //      raised by other applications than control.exe.
  //
  //  History;
  //      Mar-13-95   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  BOOL InstallF1Hook( HINSTANCE hInst, DWORD dwThreadId )
  {
      BOOL frt = FALSE;
  
      if (NULL == g_hhook)
      {
          g_hhook = SetWindowsHookEx( WH_MSGFILTER,
                  (HOOKPROC)msgprocHelpFilter,
                  hInst,
                  dwThreadId );
          if (NULL != g_hhook)
          {
              PWM_HELP = RegisterWindowMessage( szF1HELPMESSAGE );
              if (0 != PWM_HELP)
              {
                  frt = TRUE;
              }
          }
      }
  
      return( frt );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: RemoveF1Hook
  //
  //  Summary;
  //      This will remove the message filter hook that InstallF1Hook installs.
  //
  //  History;
  //      Mar-13-95   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  BOOL RemoveF1Hook( )
  {
      BOOL frt = UnhookWindowsHookEx( g_hhook );
      g_hhook = NULL;
      return( frt );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: DLLMain
  //
  //  Summary;
  //      Entry point for all DLLs
  //
  //  Notes:
  //      We only support being called from the same thread that called
  //      LoadLibrary. Because we install a message hook, and passing a
  //      zero for threadid does not work as documented.
  //
  //  History;
  //      Nov-30-94   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  BOOL APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  {
      UNREFERENCED_PARAMETER(lpReserved);
  
      BOOL frt = TRUE;
  
      switch (dwReason)
      {
      case DLL_PROCESS_ATTACH:
          g_hinst = hInstance;
          frt = InstallF1Hook( g_hinst, GetCurrentThreadId() );
          break;
  
      case DLL_PROCESS_DETACH:
          RemoveF1Hook();
          break;
  
      case DLL_THREAD_ATTACH:
          break;
  
      case DLL_THREAD_DETACH:
          break;
  
      default:
          break;
      }
      return( frt );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: LowMemoryDlg
  //
  //  Summary;
  //      Standard function for handling low memory situation
  //
  //  History;
  //      Nov-30-94   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  void LowMemoryDlg()
  {
      WCHAR szText[TEMPSTR_SIZE];
      WCHAR szTitle[TEMPSTR_SIZE];
  
      LoadString(g_hinst, IDS_CPATITLE, szTitle, TEMPSTR_SIZE);
      LoadString(g_hinst, IDS_LOWMEM, szText, TEMPSTR_SIZE);
      MessageBox (NULL, szText, szTitle, MB_OK|MB_ICONEXCLAMATION);
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: BadRegDlg
  //
  //  Summary;
  //      Standard function for handling bad registry situation
  //
  //  History;
  //      Nov-30-94   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  void BadRegDlg( HWND hwndDlg )
  {
      WCHAR szText[TEMPSTR_SIZE];
      WCHAR szTitle[TEMPSTR_SIZE];
  
      LoadString(g_hinst, IDS_CPATITLE, szTitle, TEMPSTR_SIZE);
      LoadString(g_hinst, IDS_BADREGTERM, szText, TEMPSTR_SIZE);
      MessageBox (hwndDlg, szText, szTitle, MB_OK|MB_ICONEXCLAMATION);
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: CenterDialogToScreen
  //
  //  Summary;
  //      Move the window so that it is centered on the screen
  //
  //  Arguments;
  //      hwndDlg [in] - the hwnd to the dialog to center
  //
  //  History;
  //      Dec-3-94    MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  void CenterDialogToScreen( HWND hwndDlg )
  {
      RECT rcDlg;
      INT x, y, w, h;
      INT sw, sh;
  
      sw = GetSystemMetrics( SM_CXSCREEN );
      sh = GetSystemMetrics( SM_CYSCREEN );
  
      GetWindowRect( hwndDlg, &rcDlg );
  
      w = rcDlg.right - rcDlg.left;
      h = rcDlg.bottom - rcDlg.top;
      x = (sw / 2) - (w / 2);
      y = (sh / 2) - (h / 2);
  
      MoveWindow( hwndDlg, x, y, w, h, FALSE );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: InitStaticWithService
  //  Summary;
  //      Handle the initialization of a static text with a service name
  //
  //  Arguments;
  //      hwndDlg [in] - the dialog that contains the static
  //      wID [in] - the id of the static control
  //      pszService [in] - the service display name to use
  //
  //  Notes;
  //
  //  History;
  //      Dec-05-1994 MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  void InitStaticWithService( HWND hwndDlg, UINT wID, LPCWSTR pszService )
  {
      WCHAR szText[LTEMPSTR_SIZE];
      WCHAR szTemp[LTEMPSTR_SIZE];
  
      GetDlgItemText( hwndDlg, wID, szTemp, LTEMPSTR_SIZE );
      HRESULT hr = StringCbPrintf( szText, sizeof(szText), szTemp, pszService );
      if (SUCCEEDED(hr))
          SetDlgItemText( hwndDlg, wID, szText );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: InitStaticWithService2
  //  Summary;
  //      Handle the initialization of a static text that contians two
  //      instances of a service name with the service name
  //
  //  Arguments;
  //      hwndDlg [in] - the dialog that contains the static
  //      wID [in] - the id of the static control
  //      pszService [in] - the service display name to use
  //
  //  Notes;
  //
  //  History;
  //      Dec-05-1994 MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  void InitStaticWithService2( HWND hwndDlg, UINT wID, LPCWSTR pszService )
  {
      WCHAR szText[LTEMPSTR_SIZE];
      WCHAR szTemp[LTEMPSTR_SIZE];
  
      GetDlgItemText( hwndDlg, wID, szTemp, LTEMPSTR_SIZE );
      HRESULT hr = StringCbPrintf( szText, sizeof(szText), szTemp, pszService, pszService );
      if (SUCCEEDED(hr))
          SetDlgItemText( hwndDlg, wID, szText );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: CPlApplet
  //
  //  Summary;
  //      Entry point for Comntrol Panel Applets
  //
  //  Arguments;
  //      hwndCPL [in]    - handle of Control Panel window
  //      uMsg [in]       - message
  //      lParam1 [in]    - first message parameter, usually the application number
  //      lParam2 [in]    - second message parameter
  //
  //  Return;
  //      message dependant
  //
  //  Notes;
  //
  //  History;
  //      Nov-11-1994 MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  LONG CALLBACK CPlApplet( HWND hwndCPL, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
  {
      LPCPLINFO lpCPlInfo;
      LONG_PTR iApp;
      LONG lrt = 0;
  
      iApp = (LONG_PTR) lParam1;
  
      switch (uMsg)
      {
      case CPL_INIT:      /* first message, sent once  */
          //
          // Initialize global special version information is this liccpa
          // is a special version (eg: restricted SAM, NFR, etc).
          //
  
          InitSpecialVersionInfo();
          lrt = TRUE;
          break;
  
      case CPL_GETCOUNT:  /* second message, sent once */
          lrt = 1; // we support only one application within this DLL
          break;
  
      case CPL_INQUIRE: /* third message, sent once per app */
          lpCPlInfo = (LPCPLINFO) lParam2;
          
          lpCPlInfo->idIcon = IDI_LICCPA;
          lpCPlInfo->idName = IDS_CPATITLE;
          lpCPlInfo->idInfo = IDS_CPADESC;
          lpCPlInfo->lData  = 0;
  
          break;
  
      case CPL_SELECT:    /* application icon selected */
          lrt = 1;
          break;
  
      case CPL_DBLCLK:    /* application icon double-clicked */
          //
          // Check if this is a special version of liccpa.
          //
  
          if (gSpecVerInfo.idsSpecVerWarning)
          {
              RaiseNotAvailWarning( hwndCPL );
  			break;
          }
  
          CpaDialog( hwndCPL );
          break;
  
      case CPL_STOP:      /* sent once per app. before CPL_EXIT */
          break;
  
      case CPL_EXIT:      /* sent once before FreeLibrary called */
          break;
  
      default:
          break;
      }
      return( lrt );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: CreateWSTR
  //
  //  Summary;
  //      Given a STR (ASCII or MB), allocate and translate to WSTR
  //
  //  Arguments;
  //      ppszWStr [out] - allocated & converted string
  //      pszStr [in] - string to convert
  //
  //  Return: TRUE if allocated and converted, FALSE if failed
  //
  //  History;
  //      Nov-30-94   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  BOOL CreateWSTR( LPWSTR* ppszWStr, LPSTR pszStr )
  {
      size_t cchConv;
      LPWSTR pszConv;
      BOOL frt = FALSE;
      WCHAR pszTemp[LTEMPSTR_SIZE];
  
      if (NULL == pszStr)
      {
          *ppszWStr = NULL;
          frt = TRUE;
      }
      else
      {
  #ifdef FE_SB
          // Since there was a problem in Server setup when calling setlocale or
          // linking C-runtime lib, we used Win32 API instead of mbstowcs.
          cchConv = ::MultiByteToWideChar(CP_ACP, 0,
                                          pszStr, -1,
                                          NULL, 0);
          pszConv = (LPWSTR)::GlobalAlloc( GPTR, cchConv * sizeof( WCHAR ) );
          if (NULL != pszConv)
          {
              ::MultiByteToWideChar(CP_ACP, 0,
                                    pszStr, -1,
                                    pszConv, cchConv);
              *ppszWStr = pszConv;
              frt = TRUE;
          }
  #else
          cchConv = mbstowcs( pszTemp, pszStr, LTEMPSTR_SIZE );
  
          cchConv++;
          pszConv = (LPWSTR)GlobalAlloc( GPTR, cchConv * sizeof( WCHAR ) );
          if (NULL != pszConv)
          {
              HRESULT hr = StringCchCopy( pszConv, cchConv, pszTemp );
              if (SUCCEEDED(hr))
              {
                  *ppszWStr = pszConv;
                  frt = TRUE;
              }
          }
  #endif
      }
      return( frt );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: Setup
  //
  //  Summary;
  //      Run normal setup or Perseat Setup
  //
  //  Arguments
  //      nArgs [in]      - The number of arguments in the apszArgs array
  //              If this value is 5, help button will call common help
  //              If this value is 9, help button will call the passed help
  //      apszArgs[] [in] - The argumnents passed in,
  //          [0] szRoutine - The type of setup to run (FullSetup | PerSeatSetup)
  //          [1] szHwnd - The parent Window handle, in HEX!
  //          [2] szService - The Reg Key name of the service
  //          [3] szFamilyDisplayName - The family display name of the service
  //          [4] szDisplayName - The display name of the service
  //          [5] szHelpFile - The complete path and name to help file
  //                  leave as an empty string to remove help buttons
  //          [6] szHelpContext - the DWORD to use as the main help context
  //          [7] szHCPerSeat   - the DWORD to use as the PerSeat Help context
  //          [8] szHCPerServer - the DWORD to use as the PerServer help context
  //
  //  Return:
  //      0 - sucessfull
  //      ERR_HELPPARAMS
  //      ERR_HWNDPARAM
  //      ERR_SERVICEPARAM
  //      ERR_NUMPARAMS
  //      ERR_CLASSREGFAILED
  //      ERR_INVALIDROUTINE
  //      ERR_INVALIDMODE
  //
  //  Notes:
  //
  //  History:
  //      Nov-17-94   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  const int SETUPARG_SETUP        = 0;
  const int SETUPARG_HWND         = 1;
  const int SETUPARG_SERVICE      = 2;
  const int SETUPARG_FAMILYNAME   = 3;
  const int SETUPARG_NAME         = 4;
  const int SETUPARG_HELPFILE     = 5;
  const int SETUPARG_HELPCONTEXT  = 6;
  const int SETUPARG_HCPERSEAT    = 7;
  const int SETUPARG_HCPERSERVER  = 8;
  const int SETUPARG_CERTREQUIRED = 9;
  
  const int SETUPARG_WOOPTIONAL   = 5;  // count of args without optional
  const int SETUPARG_WOPTIONAL    = 9;  // count of args with optional
  const int SETUPARG_WOPTIONALEX  = 10; // count of args with optional + certrequired extension
  
  #pragma warning (push)
  #pragma warning (disable : 4127) //avoid warning on while false
  
  INT_PTR Setup( DWORD nArgs, LPSTR apszArgs[] )
  {
      SETUPDLGPARAM dlgParam;
      INT_PTR   nError = 0;
      HWND    hwndParent = NULL;
      BOOL fCustomHelp = FALSE;
      BOOL bCertRequired = FALSE;
  
      dlgParam.pszHelpFile = (LPWSTR)LICCPA_HELPFILE;
      dlgParam.dwHelpContext = LICCPA_HELPCONTEXTMAINSETUP;
      dlgParam.dwHCPerServer = LICCPA_HELPCONTEXTPERSERVER;
      dlgParam.dwHCPerSeat = LICCPA_HELPCONTEXTPERSEAT;
      dlgParam.pszService = NULL;
      dlgParam.pszComputer = NULL;
      dlgParam.fNoExit = FALSE;
  
      do
      {
          if ((nArgs == SETUPARG_WOPTIONAL) || (nArgs == SETUPARG_WOOPTIONAL) || (nArgs == SETUPARG_WOPTIONALEX))
          {
              if (nArgs > SETUPARG_WOOPTIONAL)
              {
                  if ( ( NULL != apszArgs[SETUPARG_HELPFILE] ) && lstrcmpiA( apszArgs[SETUPARG_HELPFILE], szSETUP_DEFAULTHELP ) )
                  {
                      // help file given
                      LPWSTR pszHelpFile;
  
                      if ( CreateWSTR( &pszHelpFile, apszArgs[SETUPARG_HELPFILE] ) )
                      {
                          if (0 == lstrlen( pszHelpFile ))
                          {
                              GlobalFree( (HGLOBAL)pszHelpFile );
                              dlgParam.pszHelpFile = NULL; // should remove help buttons
                          }
                          else
                          {
                              fCustomHelp = TRUE;
                              dlgParam.pszHelpFile = pszHelpFile;
                          }
                      }
                      else
                      {
                          nError = ERR_HELPPARAMS;
                          break;
                      }
                      dlgParam.dwHelpContext = (DWORD)strtoul( apszArgs[SETUPARG_HELPCONTEXT], NULL, 0);
                      dlgParam.dwHCPerSeat = (DWORD)strtoul( apszArgs[SETUPARG_HCPERSEAT], NULL, 0);
                      dlgParam.dwHCPerServer = (DWORD)strtoul( apszArgs[SETUPARG_HCPERSERVER], NULL, 0);
                  }
  
                  if ( nArgs > SETUPARG_CERTREQUIRED )
                  {
                      // cert required / not required given
                      if ( !lstrcmpiA( szSETUP_CERTREQUIRED, apszArgs[SETUPARG_CERTREQUIRED] ) )
                      {
                          bCertRequired = TRUE;
                      }
                      else if ( lstrcmpiA( szSETUP_CERTNOTREQUIRED, apszArgs[SETUPARG_CERTREQUIRED] ) )
                      {
                          // unrecognized argument for cert required/not required
                          nError = ERR_CERTREQPARAM;
                          break;
                      }
                  }
              }
              // hwnd is in hex!
  #ifdef _WIN64
              {
                  _int64 val = 0;
                  sscanf(apszArgs[SETUPARG_HWND], "%I64x", &val);
                  hwndParent = (HWND)val;
              }
  #else
              hwndParent = (HWND)strtoul( apszArgs[SETUPARG_HWND], NULL, 16);
  #endif
              if ( !IsWindow( hwndParent ) )
              {
                  nError = ERR_HWNDPARAM;
                  hwndParent = GetActiveWindow(); // use active window as parent
                  if (!IsWindow( hwndParent ) )
                  {
                      hwndParent = GetDesktopWindow();
                  }
              }
  
              if ( CreateWSTR( &dlgParam.pszService, apszArgs[SETUPARG_SERVICE] ) &&
                   CreateWSTR( &dlgParam.pszDisplayName, apszArgs[SETUPARG_NAME] ) &&
                   CreateWSTR( &dlgParam.pszFamilyDisplayName, apszArgs[SETUPARG_FAMILYNAME] ) )
              {
                  if ( bCertRequired )
                  {
                      nError = ServiceSecuritySet( dlgParam.pszComputer, dlgParam.pszDisplayName );
                  }
                  else
                  {
                      nError = ERR_NONE;
                  }
  
                  if ( ERR_NONE == nError )
                  {
                      if (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szSETUP_PERSEAT ))
                      {
                          // use the licensing help context as the main help context
                          dlgParam.dwHelpContext = LICCPA_HELPCONTEXTLICENSING;
  
                          //
                          // Check if this is a special version of liccpa.
                          //
  
                          if (gSpecVerInfo.idsSpecVerWarning)
                          {
                              dlgParam.fNoExit = TRUE;
                              nError = SpecialSetupDialog( hwndParent,
                                                           dlgParam );
                          }
                          else
                          {
                              nError = PerSeatSetupDialog( hwndParent,
                                                           dlgParam );
                          }
                      }
                      else
                      {
                          if (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szSETUP_NORMALNOEXIT ))
                          {
                              dlgParam.fNoExit = TRUE;
                          }
  
                          //
                          // Check if this is a special version of liccpa.
                          //
  
                          if (gSpecVerInfo.idsSpecVerWarning)
                          {
                              nError = SpecialSetupDialog( hwndParent,
                                                           dlgParam );
                          }
                          else
                          {
                              nError = SetupDialog( hwndParent, dlgParam );
                          }
                      }
                  }
                  else
                  {
                      nError = ERR_SERVICEPARAM;
                  }
              }
  
              if (fCustomHelp)
              {
                  GlobalFree( (HGLOBAL)dlgParam.pszHelpFile );
              }
              GlobalFree( (HGLOBAL)dlgParam.pszService );
              GlobalFree( (HGLOBAL)dlgParam.pszDisplayName );
              GlobalFree( (HGLOBAL)dlgParam.pszFamilyDisplayName );
          }
          else
          {
              nError = ERR_NUMPARAMS;
          }
      } while (FALSE);
  
      return( nError );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: UnattendedSetup
  //
  //  Summary;
  //      This will save the passed values in the registry, keeping all
  //      licensing rules in effect and returning errorr/raising dialogs if
  //      errors occur.
  //
  //  Arguments
  //      nArgs [in]      - The number of arguments in the apszArgs array
  //      apszArgs[] [in] - The argumnents passed in,
  //          [0] szRoutine - The type of setup to run (Unattended)
  //          [1] szService - The Reg Key name of the service
  //          [2] szFamilyDisplayName - The family display name of the service
  //          [3] szDisplayName - The display name of the service
  //          [4] szMode - The string that defines the mode (PerSeat | PerServer)
  //          [5] szUsers - The DWORD to use as the count of users in PerServer mode
  //
  //  Return:
  //      0 - sucessfull
  //      ERR_HELPPARAMS
  //      ERR_HWNDPARAM
  //      ERR_SERVICEPARAM
  //      ERR_NUMPARAMS
  //      ERR_CLASSREGFAILED
  //      ERR_INVALIDROUTINE
  //      ERR_INVALIDMODE
  //
  //  Notes:
  //
  //  History:
  //      Dec-09-94   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  const int UNSETUPARG_SETUP          = 0;
  const int UNSETUPARG_SERVICE        = 1;
  const int UNSETUPARG_FAMILYNAME     = 2;
  const int UNSETUPARG_NAME           = 3;
  const int UNSETUPARG_MODE           = 4;
  const int UNSETUPARG_USERS          = 5;
  const int UNSETUPARG_CERTREQUIRED   = 6;
  
  const int UNSETUPARG_NARGSREQUIRED  = 6;
  const int UNSETUPARG_NARGSWOPTIONAL = 7;
  
  int UnattendedSetup( DWORD nArgs, LPSTR apszArgs[] )
  {
      int nError = 0;
      LPWSTR pszService;
      LPWSTR pszDisplayName;
      LPWSTR pszFamilyDisplayName;
      LICENSE_MODE lmMode;
      DWORD dwUsers;
  
      do
      {
          if ( (nArgs == UNSETUPARG_NARGSREQUIRED) || (nArgs == UNSETUPARG_NARGSWOPTIONAL) )
          {
              if ( CreateWSTR( &pszService, apszArgs[UNSETUPARG_SERVICE] ) &&
                   CreateWSTR( &pszDisplayName, apszArgs[UNSETUPARG_NAME] ) &&
                   CreateWSTR( &pszFamilyDisplayName, apszArgs[UNSETUPARG_FAMILYNAME] ) )
              {
                  nError = ERR_NONE;
  
                  if ( nArgs > UNSETUPARG_CERTREQUIRED )
                  {
                      // cert required / not required given
                      if ( !lstrcmpiA( szSETUP_CERTREQUIRED, apszArgs[UNSETUPARG_CERTREQUIRED] ) )
                      {
                          nError = ServiceSecuritySet( NULL, pszDisplayName );
                      }
                      else if ( lstrcmpiA( szSETUP_CERTNOTREQUIRED, apszArgs[UNSETUPARG_CERTREQUIRED] ) )
                      {
                          // unrecognized argument for cert required/not required
                          nError = ERR_CERTREQPARAM;
                      }
                  }
  
                  if ( ERR_NONE == nError )
                  {
                      //
                      // Check if this is a special version of liccpa.
                      //
  
                      if (gSpecVerInfo.idsSpecVerWarning)
                      {
                          lmMode  = gSpecVerInfo.lmSpecialMode;
                          dwUsers = gSpecVerInfo.dwSpecialUsers;
                      }
                      else
                      {
                          if (0 == lstrcmpiA( apszArgs[UNSETUPARG_MODE],
                                              szUNATTENDED_PERSERVER ))
                          {
                              lmMode = LICMODE_PERSERVER;
                          }
                          else if (0 == lstrcmpiA( apszArgs[UNSETUPARG_MODE],
                                                   szUNATTENDED_PERSEAT ))
                          {
                              lmMode = LICMODE_PERSEAT;
                          }
                          else
                          {
                              nError = ERR_INVALIDMODE;
                              break;
                          }
                          dwUsers = (DWORD)strtoul( apszArgs[UNSETUPARG_USERS],
                                                    NULL, 0);
                      }
  
                      nError = UpdateReg( NULL,
                              pszService,
                              pszFamilyDisplayName,
                              pszDisplayName,
                              lmMode,
                              dwUsers );
                  }
  
                  GlobalFree( (HGLOBAL)pszService );
                  GlobalFree( (HGLOBAL)pszDisplayName );
                  GlobalFree( (HGLOBAL)pszFamilyDisplayName );
              }
              else
              {
                  nError = ERR_SERVICEPARAM;
              }
          }
          else
          {
              nError = ERR_NUMPARAMS;
          }
      } while (FALSE);
  
      return( nError );
  }
  //-------------------------------------------------------------------
  //
  //  Function: RemoteSetup
  //
  //  Summary;
  //      Run normal setup, Perseat Setup, normal setup without exit remotely
  //
  //  Arguments
  //      nArgs [in]      - The number of arguments in the apszArgs array
  //              If this value is 6, help button will call common help
  //              If this value is 10, help button will call the passed help
  //      apszArgs[] [in] - The argumnents passed in,
  //          [0] szRoutine - The type of setup to run
  //          [1] szComputer - the name of the computer to setup on (\\name)
  //          [2] szHwnd - The parent Window handle, in HEX!
  //          [3] szService - The Reg Key name of the service
  //          [4] szFamilyDisplayName - The family display name of the service
  //          [5] szDisplayName - The display name of the service
  //          [6] szHelpFile - The complete path and name to help file
  //                  leave as an empty string to remove help buttons
  //          [7] szHelpContext - the DWORD to use as the main help context
  //          [8] szHCPerSeat   - the DWORD to use as the PerSeat Help context
  //          [9] szHCPerServer - the DWORD to use as the PerServer help context
  //
  //  Return:
  //      0 - sucessfull
  //      ERR_PERMISSIONDENIED
  //      ERR_HELPPARAMS
  //      ERR_HWNDPARAM
  //      ERR_SERVICEPARAM
  //      ERR_NUMPARAMS
  //      ERR_CLASSREGFAILED
  //      ERR_INVALIDROUTINE
  //      ERR_INVALIDMODE
  //
  //  Notes:
  //
  //  History:
  //      Apr-26-95   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  const int REMSETUPARG_SETUP         = 0;
  const int REMSETUPARG_COMPUTER      = 1;
  const int REMSETUPARG_HWND          = 2;
  const int REMSETUPARG_SERVICE       = 3;
  const int REMSETUPARG_FAMILYNAME    = 4;
  const int REMSETUPARG_NAME          = 5;
  const int REMSETUPARG_HELPFILE      = 6;
  const int REMSETUPARG_HELPCONTEXT   = 7;
  const int REMSETUPARG_HCPERSEAT     = 8;
  const int REMSETUPARG_HCPERSERVER   = 9;
  const int REMSETUPARG_CERTREQUIRED  = 10;
  
  const int REMSETUPARG_WOOPTIONAL    = 6; // count of args without optional
  const int REMSETUPARG_WOPTIONAL = 10; // count of args with optional
  const int REMSETUPARG_WOPTIONALEX   = 11; // count of args with optional + certrequired
  
  INT_PTR RemoteSetup( DWORD nArgs, LPSTR apszArgs[] )
  {
      SETUPDLGPARAM dlgParam;
      INT_PTR   nError = 0;
      HWND    hwndParent = NULL;
      BOOL fCustomHelp = FALSE;
      BOOL bCertRequired = FALSE;
  
      dlgParam.pszHelpFile = (LPWSTR)LICCPA_HELPFILE;
      dlgParam.dwHelpContext = LICCPA_HELPCONTEXTMAINSETUP;
      dlgParam.dwHCPerServer = LICCPA_HELPCONTEXTPERSERVER;
      dlgParam.dwHCPerSeat = LICCPA_HELPCONTEXTPERSEAT;
      dlgParam.pszService = NULL;
      dlgParam.fNoExit = FALSE;
  
      do
      {
          nError = ERR_NONE;
  
          if ((nArgs == REMSETUPARG_WOPTIONAL) || (nArgs == REMSETUPARG_WOOPTIONAL) || (nArgs == REMSETUPARG_WOPTIONALEX))
          {
              if (nArgs > REMSETUPARG_WOOPTIONAL)
              {
                  if ( ( NULL != apszArgs[REMSETUPARG_HELPFILE] ) && lstrcmpiA( apszArgs[REMSETUPARG_HELPFILE], szSETUP_DEFAULTHELP ) )
                  {
                      LPWSTR pszHelpFile;
  
                      if ( CreateWSTR( &pszHelpFile, apszArgs[REMSETUPARG_HELPFILE] ) )
                      {
                          if (0 == lstrlen( pszHelpFile ))
                          {
                              GlobalFree( (HGLOBAL)pszHelpFile );
                              dlgParam.pszHelpFile = NULL; // should remove help buttons
                          }
                          else
                          {
                              fCustomHelp = TRUE;
                              dlgParam.pszHelpFile = pszHelpFile;
                          }
                      }
                      else
                      {
                          nError = ERR_HELPPARAMS;
                          break;
                      }
                      dlgParam.dwHelpContext = (DWORD)strtoul( apszArgs[REMSETUPARG_HELPCONTEXT], NULL, 0);
                      dlgParam.dwHCPerSeat = (DWORD)strtoul( apszArgs[REMSETUPARG_HCPERSEAT], NULL, 0);
                      dlgParam.dwHCPerServer = (DWORD)strtoul( apszArgs[REMSETUPARG_HCPERSERVER], NULL, 0);
                  }
  
                  if ( nArgs > REMSETUPARG_CERTREQUIRED )
                  {
                      // cert required / not required given
                      if ( !lstrcmpiA( szSETUP_CERTREQUIRED, apszArgs[REMSETUPARG_CERTREQUIRED] ) )
                      {
                          bCertRequired = TRUE;
                      }
                      else if ( lstrcmpiA( szSETUP_CERTNOTREQUIRED, apszArgs[REMSETUPARG_CERTREQUIRED] ) )
                      {
                          // unrecognized argument for cert required/not required
                          nError = ERR_CERTREQPARAM;
                          break;
                      }
                  }
              }
              // hwnd is in hex!
  #ifdef _WIN64
              {
                  _int64 val = 0;
                  sscanf(apszArgs[REMSETUPARG_HWND], "%I64x", &val);
                  hwndParent = (HWND)val;
              }
  #else
              hwndParent = (HWND)strtoul( apszArgs[REMSETUPARG_HWND], NULL, 16);
  #endif
              if ( !IsWindow( hwndParent ) )
              {
                  nError = ERR_HWNDPARAM;
                  hwndParent = GetActiveWindow(); // use active window as parent
                  if (!IsWindow( hwndParent ) )
                  {
                      hwndParent = GetDesktopWindow();
                  }
              }
  
              if ( CreateWSTR( &dlgParam.pszService, apszArgs[REMSETUPARG_SERVICE] ) &&
                   CreateWSTR( &dlgParam.pszDisplayName, apszArgs[REMSETUPARG_NAME] ) &&
                   CreateWSTR( &dlgParam.pszComputer, apszArgs[REMSETUPARG_COMPUTER] ) &&
                   CreateWSTR( &dlgParam.pszFamilyDisplayName, apszArgs[REMSETUPARG_FAMILYNAME] ) )
              {
                  if ( bCertRequired )
                  {
                      nError = ServiceSecuritySet( dlgParam.pszComputer, dlgParam.pszDisplayName );
                  }
                  else
                  {
                      nError = ERR_NONE;
                  }
  
                  if ( ERR_NONE == nError )
                  {
                      if (0 == lstrcmpiA( apszArgs[REMSETUPARG_SETUP], szREMOTESETUP_PERSEAT ))
                      {
                          // use the licensing help context as the main help context
                          dlgParam.dwHelpContext = LICCPA_HELPCONTEXTLICENSING;
  
                          //
                          // Check if this is a special version of liccpa.
                          //
  
                          if (gSpecVerInfo.idsSpecVerWarning)
                          {
                              dlgParam.fNoExit = TRUE;
                              nError = SpecialSetupDialog( hwndParent,
                                                           dlgParam );
                          }
                          else
                          {
                              nError = PerSeatSetupDialog( hwndParent,
                                                           dlgParam );
                          }
                      }
                      else
                      {
                          if (0 == lstrcmpiA( apszArgs[REMSETUPARG_SETUP], szREMOTESETUP_NORMALNOEXIT ))
                          {
                              dlgParam.fNoExit = TRUE;
                          }
  
                          //
                          // Check if this is a special version of liccpa.
                          //
  
                          if (gSpecVerInfo.idsSpecVerWarning)
                          {
                              nError = SpecialSetupDialog( hwndParent,
                                                           dlgParam );
                          }
                          else
                          {
                              nError = SetupDialog( hwndParent, dlgParam );
                          }
                      }
                  }
              }
              else
              {
                  nError = ERR_SERVICEPARAM;
              }
  
              if (fCustomHelp)
              {
                  GlobalFree( (HGLOBAL)dlgParam.pszHelpFile );
              }
              GlobalFree( (HGLOBAL)dlgParam.pszService );
              GlobalFree( (HGLOBAL)dlgParam.pszDisplayName );
              GlobalFree( (HGLOBAL)dlgParam.pszFamilyDisplayName );
              GlobalFree( (HGLOBAL)dlgParam.pszComputer );
          }
          else
          {
              nError = ERR_NUMPARAMS;
          }
      } while (FALSE);
  
      return( nError );
  }
  
  //-------------------------------------------------------------------
  //
  //  Function: RemoteUnattendedSetup
  //
  //  Summary;
  //      This will save the passed values in the registry, keeping all
  //      licensing rules in effect and returning errorr/raising dialogs if
  //      errors occur. This is done remotely on the computer specified.
  //
  //  Arguments
  //      nArgs [in]      - The number of arguments in the apszArgs array
  //      apszArgs[] [in] - The argumnents passed in,
  //          [0] szRoutine - The type of setup to run (Unattended)
  //          [1] szComputer - the name of the computer to setup on (\\name)
  //          [2] szService - The Reg Key name of the service
  //          [3] szFamilyDisplayName - The family display name of the service
  //          [4] szDisplayName - The display name of the service
  //          [5] szMode - The string that defines the mode (PerSeat | PerServer)
  //          [6] szUsers - The DWORD to use as the count of users in PerServer mode
  //
  //  Return:
  //      0 - sucessfull
  //      ERR_PERMISSIONDENIED
  //      ERR_HELPPARAMS
  //      ERR_HWNDPARAM
  //      ERR_SERVICEPARAM
  //      ERR_USERSPARAM
  //      ERR_NUMPARAMS
  //      ERR_CLASSREGFAILED
  //      ERR_INVALIDROUTINE
  //      ERR_INVALIDMODE
  //
  //  Notes:
  //
  //  History:
  //      Apr-26-95   MikeMi  Created
  //
  //-------------------------------------------------------------------
  
  const int REMUNSETUPARG_SETUP           = 0;
  const int REMUNSETUPARG_COMPUTER        = 1;
  const int REMUNSETUPARG_SERVICE         = 2;
  const int REMUNSETUPARG_FAMILYNAME      = 3;
  const int REMUNSETUPARG_NAME            = 4;
  const int REMUNSETUPARG_MODE            = 5;
  const int REMUNSETUPARG_USERS           = 6;
  const int REMUNSETUPARG_CERTREQUIRED    = 7;
  
  const int REMUNSETUPARG_NARGSREQUIRED   = 7;
  const int REMUNSETUPARG_NARGSWOPTIONAL  = 8;
  
  int RemoteUnattendedSetup( DWORD nArgs, LPSTR apszArgs[] )
  {
      int nError = 0;
      LPWSTR pszService;
      LPWSTR pszDisplayName;
      LPWSTR pszFamilyDisplayName;
      LPWSTR pszComputerName;
  
      LICENSE_MODE lmMode;
      DWORD dwUsers;
  
  
      do
      {
          if ( (nArgs == REMUNSETUPARG_NARGSREQUIRED) || (nArgs == REMUNSETUPARG_NARGSWOPTIONAL) )
          {
              if ( CreateWSTR( &pszService, apszArgs[REMUNSETUPARG_SERVICE] ) &&
                   CreateWSTR( &pszDisplayName, apszArgs[REMUNSETUPARG_NAME] ) &&
                   CreateWSTR( &pszFamilyDisplayName, apszArgs[REMUNSETUPARG_FAMILYNAME] ) &&
                   CreateWSTR( &pszComputerName, apszArgs[REMUNSETUPARG_COMPUTER] ) )
              {
                  nError = ERR_NONE;
  
                  if ( nArgs > REMUNSETUPARG_CERTREQUIRED )
                  {
                      // cert required / not required given
                      if ( !lstrcmpiA( szSETUP_CERTREQUIRED, apszArgs[REMUNSETUPARG_CERTREQUIRED] ) )
                      {
                          nError = ServiceSecuritySet( pszComputerName, pszDisplayName );
                      }
                      else if ( lstrcmpiA( szSETUP_CERTNOTREQUIRED, apszArgs[REMUNSETUPARG_CERTREQUIRED] ) )
                      {
                          // unrecognized argument for cert required/not required
                          nError = ERR_CERTREQPARAM;
                      }
                  }
  
                  if ( ERR_NONE == nError )
                  {
                      //
                      // Check if this is a special version of liccpa.
                      //
  
                      if (gSpecVerInfo.idsSpecVerWarning)
                      {
                          lmMode  = gSpecVerInfo.lmSpecialMode;
                          dwUsers = gSpecVerInfo.dwSpecialUsers;
                      }
                      else
                      {
                          if (0 == lstrcmpiA( apszArgs[REMUNSETUPARG_MODE],
                                              szUNATTENDED_PERSERVER ))
                          {
                              lmMode = LICMODE_PERSERVER;
                          }
                          else if (0 == lstrcmpiA( apszArgs[REMUNSETUPARG_MODE],
                                                   szUNATTENDED_PERSEAT ))
                          {
                              lmMode = LICMODE_PERSEAT;
                          }
                          else
                          {
                              nError = ERR_INVALIDMODE;
                              break;
                          }
                          dwUsers = (DWORD)strtoul(
                                              apszArgs[REMUNSETUPARG_USERS],
                                              NULL, 0);
                      }
  
                      nError = UpdateReg( pszComputerName,
                              pszService,
                              pszFamilyDisplayName,
                              pszDisplayName,
                              lmMode,
                              dwUsers );
                  }
  
                  if(pszService != NULL)
                  {
                      GlobalFree( (HGLOBAL)pszService );
                  }
                  if(pszDisplayName != NULL)
                  {
                      GlobalFree( (HGLOBAL)pszDisplayName );
                  }
                  if(pszFamilyDisplayName != NULL)
                  {
                      GlobalFree( (HGLOBAL)pszFamilyDisplayName );
                  }
                  if(pszComputerName != NULL)
                  {
                      GlobalFree( (HGLOBAL)pszComputerName );
                  }
              }
              else
              {
                  nError = ERR_SERVICEPARAM;
              }
          }
          else
          {
              nError = ERR_NUMPARAMS;
          }
      } while (FALSE);
  
  
      return( nError );
  }
  
  #pragma warning (pop) //4127
  
  //-------------------------------------------------------------------
  //
  //  Function: CPlSetup
  //
  //  Summary;
  //      Dll entry point for License Mode Setup, to be used from Setup
  //      programs.
  //
  //  Arguments
  //      nArgs [in]      - The number of arguments in the apszArgs array
  //      apszArgs[] [in] - The argumnents passed in,
  //          [0] szRoutine - The type of setup to run
  //                  FullSetup | RemoteFullSetup |
  //                  PerSeatSetup | RemotePerSeatSetup |
  //                  Unattended |  RemoteUnattended |
  //                  FullSetupNoexit | RemoteFullSetupNoexit
  //      ppszResult [out]- The result string
  //
  //  Return:
  //
  //  Notes:
  //
  //  History:
  //      Nov-17-94   MikeMi  Created
  //      Apr-26-95   MikeMi  Added remoting routines
  //
  //-------------------------------------------------------------------
  
  BOOL APIENTRY CPlSetup( DWORD nArgs, LPSTR apszArgs[], LPSTR *ppszResult )
  {
      INT_PTR   nError = 0;
      BOOL  frt = TRUE;
  
      //
      // Initialize global special version information is this liccpa
      // is a special version (eg: restricted SAM, NFR, etc).
      //
  
      InitSpecialVersionInfo();
  
      if ((0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szSETUP_PERSEAT )) ||
          (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szSETUP_NORMAL )) ||
          (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szSETUP_NORMALNOEXIT )) )
      {
          nError = Setup( nArgs, apszArgs );
      }
      else if (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szSETUP_UNATTENDED ))
      {
          nError = UnattendedSetup( nArgs, apszArgs );
      }
      else if ((0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szREMOTESETUP_PERSEAT )) ||
          (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szREMOTESETUP_NORMAL )) ||
          (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szREMOTESETUP_NORMALNOEXIT )) )
      {
          nError = RemoteSetup( nArgs, apszArgs );
      }
      else if (0 == lstrcmpiA( apszArgs[SETUPARG_SETUP], szREMOTESETUP_UNATTENDED ))
      {
          nError = RemoteUnattendedSetup( nArgs, apszArgs );
      }
      else
      {
          nError = ERR_INVALIDROUTINE;
      }
  
      // prepare error for return
      switch (nError)
      {
      case 0:
          *ppszResult = szSETUP_EXIT;
          break;
  
      case ERR_NONE:
          *ppszResult = szSETUP_OK;
          break;
  
      case ERR_PERMISSIONDENIED:
          frt = FALSE;
          *ppszResult = szSETUP_SECURITY;
          break;
  
      case ERR_NOREMOTESERVER:
          frt = FALSE;
          *ppszResult = szSETUP_NOREMOTE;
          break;
  
      case ERR_DOWNLEVEL:
          frt = FALSE;
          *ppszResult = szSETUP_DOWNLEVEL;
          break;
  
      default:
          *ppszResult = szSETUP_ERROR;
          frt = FALSE;
          break;
      }
  
      return( frt );
  }
  