//----------------------------------------------------------------------------
//
// SCRNSAVE.C      --    skeleton for screen saver application
//
//    4/5/94 francish   merged NT and Win4 saver code, folded in SCRNSAVE.SCR
//
//----------------------------------------------------------------------------

#define WIN31
#include <windows.h>
#include <windowsx.h>
#include "scrnsave.h"
#include <regstr.h>
#include <commctrl.h>
#include <imm.h>

#define DBG_MSGS    0

const TCHAR szScreenSaverKey[] = REGSTR_PATH_SCREENSAVE;
TCHAR szPasswordActiveValue[] = REGSTR_VALUE_USESCRPASSWORD;
const TCHAR szPasswordValue[] = REGSTR_VALUE_SCRPASSWORD;
TCHAR szPwdDLL[] = TEXT("PASSWORD.CPL");
CHAR szFnName[] = "VerifyScreenSavePwd";        // Proc name, must be ANSI
TCHAR szImmDLL[] = TEXT("IMM32.DLL");
CHAR szImmFnc[] = "ImmAssociateContext";        // Proc name, must be ANSI
#if 0
TCHAR szCoolSaverHacks[] = REGSTR_PATH_SETUP TEXT("\\Screen Savers");
TCHAR szMouseThreshold[] = TEXT("Mouse Threshold");
TCHAR szPasswordDelay[] = TEXT("Password Delay");
#endif

typedef BOOL (FAR PASCAL * VERIFYPWDPROC) (HWND);
typedef HIMC (FAR PASCAL * IMMASSOCPROC) (HWND,HIMC);


//----------------------------------------------------------------------------
// variables declared in SCRNSAVE.H
HINSTANCE hMainInstance = 0;
HWND hMainWindow = 0;
BOOL fChildPreview = FALSE;



//----------------------------------------------------------------------------
// other globals
POINT ptMouse;
BOOL fClosing = FALSE;
BOOL fCheckingPassword = FALSE;
HINSTANCE hInstPwdDLL = NULL;
VERIFYPWDPROC VerifyPassword = NULL;
static BOOL preview_like_fullscreen = FALSE;
static UINT uShellAutoPlayQueryMessage = 0;
HINSTANCE hInstImm = NULL;
IMMASSOCPROC ImmFnc = NULL;
HIMC hPrevImc = (HIMC)0L;


static BOOL fOnWin95 = FALSE;  //TRUE if on Chicago, FALSE if on Cairo

//----------------------------------------------------------------------------
// random junk
DWORD dwWakeThreshold = 4;  //default to slight movement
DWORD dwPasswordDelay = 0;
DWORD dwBlankTime = 0;
#define MAX_PASSWORD_DELAY_IN_SECONDS (60)

BYTE  bACLineStatus = AC_LINE_UNKNOWN;    // Last state of AC line 

//----------------------------------------------------------------------------
// forward declarations of internal fns
static INT_PTR DoScreenSave( HWND hParent );
static INT_PTR DoSaverPreview( LPCTSTR szUINTHandle );
static INT_PTR DoConfigBox( HWND hParent );
static INT_PTR DoChangePw( LPCTSTR szUINTHandle );
static BOOL DoPasswordCheck( HWND hParent );
VOID LoadPwdDLL(VOID);
VOID UnloadPwdDLL(VOID);


//----------------------------------------------------------------------------
// helper for time
static DWORD
GetElapsedTime(DWORD from, DWORD to)
{
    return (to >= from)? (to - from) : (1 + to + (((DWORD)-1) - from));
}

//----------------------------------------------------------------------------
// helper to convert text to unsigned int
static UINT_PTR
atoui( LPCTSTR szUINT )
{
   UINT_PTR uValue = 0;

   while( ( *szUINT >= TEXT('0') ) && ( *szUINT <= TEXT('9') ) )
      uValue = ( ( uValue * 10 ) + ( *szUINT++ - TEXT('0') ) );

   return uValue;
}


//----------------------------------------------------------------------------
// Local reboot and hotkey control (on Win95)
static void
HogMachine( BOOL value )
{
    BOOL dummy;

    //
    // NT is always secure, therefore we don't need to call this on Cairo/NT
    //
    if (fOnWin95) {
        SystemParametersInfo( SPI_SCREENSAVERRUNNING, value, &dummy, 0 );
    }
}


//----------------------------------------------------------------------------
// entry point (duh)
INT_PTR PASCAL
WinMainN( HINSTANCE hInst, HINSTANCE hPrev, LPTSTR szCmdLine, int nCmdShow )
{
    LPCTSTR pch = szCmdLine;
    HWND hParent = 0;
    OSVERSIONINFO osvi;
    INITCOMMONCONTROLSEX icce = {0};

	ZeroMemory(&icce, sizeof(icce));
	icce.dwSize = sizeof(icce);
	icce.dwICC = ICC_TAB_CLASSES;
	InitCommonControlsEx(&icce);

    hMainInstance = hInst;

    osvi.dwOSVersionInfoSize = sizeof(osvi);
    fOnWin95 = (GetVersionEx(&osvi) &&
                osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);

    _try
    {
      for(;;) switch( *pch )
      {
          case TEXT('S'):
          case TEXT('s'):
              return DoScreenSave( NULL );

          case TEXT('L'):
          case TEXT('l'):
              // special switch for tests such as WinBench
              // this is NOT a hack to make bechmarks look good
              // it's a hack to allow you to benchmark a screen saver
              // many bechmarking apps require the whole screen in foreground
              // which makes it hard to measure how a screensaver adds CPU load
              // you must provide a parent window (just like preview mode)
              preview_like_fullscreen = TRUE;
          case TEXT('P'):
          case TEXT('p'):
              do pch++; while( *pch == TEXT(' ') );  // skip to the good stuff
              return DoSaverPreview( pch );

          case TEXT('A'):
          case TEXT('a'):
              if (!fOnWin95)
                  return -1;
              do pch++; while( *pch == TEXT(' ') );  // skip to the good stuff
              return DoChangePw( pch );

          case TEXT('C'):
          case TEXT('c'): {
              HWND hwndParent = NULL
              ;
              // Look for optional parent window after the "C",
              // syntax is "C:hwnd_value"
              if (*(++pch) == TEXT(':')) {
                   hwndParent = (HWND)atoui( ++pch );
              }

              if (hwndParent == NULL || !IsWindow(hwndParent))
                   hwndParent = GetForegroundWindow();

              return DoConfigBox( hwndParent );
          }

          case TEXT('\0'):
              return DoConfigBox( NULL );

          case TEXT(' '):
          case TEXT('-'):
          case TEXT('/'):
              pch++;   // skip spaces and common switch prefixes
              break;

          default:
              return -1;
      }
    }
    _except(UnhandledExceptionFilter(GetExceptionInformation()))
    {
      // don't leave local reboot and hotkeys disabled on Win95
      HogMachine( FALSE );
    }

    return -1;
}


//----------------------------------------------------------------------------
// default screen-saver proc, declared in SCRNSAVE.H
// intended to be called by the consumer's ScreenSaverProc where
// DefWindowProc would normally be called
LRESULT WINAPI
DefScreenSaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
#if DBG_MSGS
    TCHAR szBuff[80];

    wsprintf( szBuff, TEXT("*** DefSSP received:\t0x%04lx 0x%08lx 0x%08lx\n"), uMsg, wParam, lParam );
    OutputDebugString(szBuff);
#endif
    SYSTEM_POWER_STATUS sps;
    BYTE bCurrentLineStatus;

   if( !fChildPreview && !fClosing )
   {
      switch( uMsg )
      {
         case WM_CLOSE:
            //
            // Only do password check if on Windows 95.  WinNT (Cairo) has
            // the password check built into the security desktop for
            // C2 compliance.
            //
            if (fOnWin95) {
                if( !DoPasswordCheck( hWnd ) )
                {
                    GetCursorPos( &ptMouse );  // re-establish
                    return FALSE;
                }
            }
            break;

         case SCRM_VERIFYPW:
            if (fOnWin95)
                return ( VerifyPassword? (LRESULT)VerifyPassword( hWnd ) : 1L );
            break;

         default:
         {
            POINT ptMove, ptCheck;

            if( fCheckingPassword )
                break;

            switch( uMsg )
            {
                case WM_SHOWWINDOW:
                    if( (BOOL)wParam )
                    SetCursor( NULL );
                    break;

                case WM_SETCURSOR:
                    SetCursor( NULL );
                    return TRUE;

                case WM_MOUSEMOVE:
                    GetCursorPos( &ptCheck );
                    if( ( ptMove.x = ptCheck.x - ptMouse.x ) && ( ptMove.x < 0 ) )
                        ptMove.x *= -1;
                    if( ( ptMove.y = ptCheck.y - ptMouse.y ) && ( ptMove.y < 0 ) )
                        ptMove.y *= -1;
                    if( ((DWORD)ptMove.x + (DWORD)ptMove.y) > dwWakeThreshold )
                    {
                        PostMessage( hWnd, WM_CLOSE, 0, 0l );
                        ptMouse = ptCheck;
                    }
                    break;


                //
                // Handle Power Management event
                //
                case WM_POWERBROADCAST:
                    switch (wParam)
                    {
                        case PBT_APMPOWERSTATUSCHANGE:
                        if (GetSystemPowerStatus(&sps)) {
                            bCurrentLineStatus = sps.ACLineStatus;
                        }
                        else {
                            // we can't determine the power status, use default
                            bCurrentLineStatus = AC_LINE_UNKNOWN;
                        }

                        // If the current line status differs from the previous
                        // exit the screen saver, otherwise just keep running
                        if (bCurrentLineStatus != bACLineStatus) {
                            bACLineStatus = bCurrentLineStatus;
                            goto PostClose;
                        }
                        else {
                            bACLineStatus = bCurrentLineStatus;
                        }

                        break;

                        case PBT_APMRESUMECRITICAL:
                        case PBT_APMRESUMESUSPEND:
                        case PBT_APMRESUMESTANDBY:
                        case PBT_APMRESUMEAUTOMATIC:

                        // If the system is resuming from a real suspend
                        // (as opposed to a failed suspend) deactivate
                        // the screensaver.
                        if ((lParam & PBTF_APMRESUMEFROMFAILURE) == 0)
                        {
                            goto PostClose;
                        }
                        break;

                        default:
                        {
                            goto PostClose;
                        }
                    }
                    break;

                case WM_POWER:
                    //
                    // a critical resume does not generate a WM_POWERBROADCAST
                    // to windows for some reason, but it does generate an old
                    // WM_POWER message.
                    //
                    if (wParam == PWR_CRITICALRESUME)
                        goto PostClose;
                    break;

                case WM_ACTIVATEAPP:
                    if( wParam ) break;
                case WM_LBUTTONDOWN:
                case WM_MBUTTONDOWN:
                case WM_RBUTTONDOWN:
                case WM_KEYDOWN:
                case WM_SYSKEYDOWN:
PostClose:
                    PostMessage( hWnd, WM_CLOSE, 0, 0l );
                    break;
            }
         }
      }
   }

   //
   // the shell sends this message to the foreground window before running an
   // AutoPlay app. On Win95, we return 1 to cancel autoplay if we are password protected
   //
   // On WinNT, secure screen savers run on a secure separate desktop, and will never see
   // this message, therefore, this code will never get executed.
   //
   //
   // APPCOMPAT -
   // On NT we don't want to take down the screen saver unless it is running
   // on the same desktop as the autoplay shell.  There is code in the
   // NT autoplay shell that looks for this and does not run the app if
   // that is the case; however, I not positive that the uShellAutoPlayQueryMessage
   // will not go between desktops.  (BradG assures me that it will not, but you
   // never know.)  If secure screensavers on NT randomly close when you put
   // an autoplay cd in the drive, then this code should be examined closely.
   //
   if ((uMsg == uShellAutoPlayQueryMessage) && uMsg)
   {
      PostMessage(hWnd, WM_CLOSE, 0, 0L);
      return (VerifyPassword != NULL);
   }

   return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

//----------------------------------------------------------------------------
// This window procedure takes care of important stuff before calling the
// consumer's ScreenSaverProc.  This helps to prevent us from getting hosed
// by wacky consumer code.
LRESULT WINAPI
RealScreenSaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
   switch( uMsg )
   {
      case WM_CREATE:
         // screen saver does not need the IME
         if ((hInstImm = GetModuleHandle(szImmDLL)) &&
             (ImmFnc = (IMMASSOCPROC)GetProcAddress(hInstImm,szImmFnc)))
             hPrevImc = ImmFnc(hWnd, (HIMC)0);

         // establish the mouse position
         GetCursorPos( &ptMouse );

         if( !fChildPreview )
            SetCursor( NULL );

         break;

      case WM_DESTROY:
         // screen saver does not need the IME
         if( hInstImm && ImmFnc && hPrevImc )
            ImmFnc(hWnd, hPrevImc);

         PostQuitMessage( 0 );
         break;

      case WM_SETTEXT:
         // don't let some fool change our title
         // we need to be able to use FindWindow() to find running instances
         // of full-screen windows screen savers
         // NOTE: USER slams our title in during WM_NCCREATE by calling the
         // defproc for WM_SETTEXT directly, so the initial title will get
         // there.  If this ever changes, we can simply set a bypass flag
         // during WM_NCCREATE processing.
         return FALSE;

      case WM_SYSCOMMAND:
         if (!fChildPreview)
         {
            switch (wParam)
            {
               case SC_NEXTWINDOW:       // no Alt-tabs
               case SC_PREVWINDOW:       // no shift-alt-tabs
               case SC_SCREENSAVE:       // no more screensavers
                  return FALSE;
                  break;
                case SC_MONITORPOWER:
                  //
                  // The monitor is shutting down.  Tell our client that he needs to
                  // cleanup and exit.
                  //
                  PostMessage( hWnd, WM_CLOSE, 0, 0l );
                  break;
            }
         }
         break;

      case WM_HELP:
      case WM_CONTEXTMENU:
         if( fChildPreview )
         {
            // if we're in preview mode, pump the help stuff to our owner
            HWND hParent = GetParent( hWnd );

            if( hParent && IsWindow( hParent ) )
               PostMessage( hParent, uMsg, (WPARAM)hParent, lParam );
               return TRUE;
         }
         break;

      case WM_TIMER:
         if( fClosing )
            return FALSE;
         Sleep( 0 );
         break;

      case WM_MOUSEMOVE:
      case WM_LBUTTONDOWN:
      case WM_MBUTTONDOWN:
      case WM_RBUTTONDOWN:
      case WM_KEYDOWN:
      case WM_SYSKEYDOWN:
         if( fClosing )
            return DefWindowProc( hWnd, uMsg, wParam, lParam );
         break;

      case WM_PAINT:
         if( fClosing )
            return DefWindowProc( hWnd, uMsg, wParam, lParam );
         if( !fChildPreview )
            SetCursor( NULL );
         break;
   }

   return ScreenSaverProc( hWnd, uMsg, wParam, lParam );
}

static void
InitRealScreenSave()
{
#if 0
   HKEY hkey;

   if (RegOpenKey(HKEY_CURRENT_USER, szCoolSaverHacks, &hkey) ==
      ERROR_SUCCESS)
   {
      DWORD data, len, type;

      len = sizeof(data);
      if ((RegQueryValueEx(hkey, szMouseThreshold, NULL, &type,
         (LPBYTE)&data, &len) == ERROR_SUCCESS) && (type == REG_DWORD))
      {
         dwWakeThreshold = max(dwWakeThreshold, data);
      }

      len = sizeof(data);
      if ((RegQueryValueEx(hkey, szPasswordDelay, NULL, &type,
         (LPBYTE)&data, &len) == ERROR_SUCCESS) && (type == REG_DWORD) && data)
      {
         data = min(MAX_PASSWORD_DELAY_IN_SECONDS, data);
         dwPasswordDelay = data * 1000;
         dwBlankTime = GetTickCount();
      }
   }
#endif

   LoadPwdDLL();
}

//----------------------------------------------------------------------------

static INT_PTR
DoScreenSave( HWND hParent )
{
   LPCTSTR pszWindowClass = TEXT("WindowsScreenSaverClass");
   LPCTSTR pszWindowTitle;

   WNDCLASS cls;
   MSG      msg;
   UINT     uStyle;
   UINT     uExStyle;
   int      ncx, ncy;
   int      nx, ny;

   SYSTEM_POWER_STATUS sps;

   cls.hCursor        = NULL;
   cls.hIcon          = LoadIcon( hMainInstance, MAKEINTATOM( ID_APP ) );
   cls.lpszMenuName   = NULL;
   cls.lpszClassName  = pszWindowClass;
   cls.hbrBackground  = GetStockObject( BLACK_BRUSH );
   cls.hInstance      = hMainInstance;
   cls.style          = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_OWNDC;
   cls.lpfnWndProc    = RealScreenSaverProc;
   cls.cbWndExtra     = 0;
   cls.cbClsExtra     = 0;

   if( hParent )
   {
      RECT rcParent;
      GetClientRect( hParent, &rcParent );
      ncx = rcParent.right;
      ncy = rcParent.bottom;
      nx  = 0;
      ny  = 0;
      uStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN;
      uExStyle = 0;

      fChildPreview = TRUE;
      pszWindowTitle = TEXT("Preview");      // MUST differ from full screen
   }
   else
   {
      HWND hOther;

#ifdef SM_CXVIRTUALSCREEN
      nx  = GetSystemMetrics( SM_XVIRTUALSCREEN );
      ny  = GetSystemMetrics( SM_YVIRTUALSCREEN );
      ncx = GetSystemMetrics( SM_CXVIRTUALSCREEN );
      ncy = GetSystemMetrics( SM_CYVIRTUALSCREEN );

      if (ncx == 0 || ncy == 0)
#endif
      {
        RECT rc;
        HDC hdc = GetDC(NULL);
        GetClipBox(hdc, &rc);
        ReleaseDC(NULL, hdc);
        nx = rc.left;
        ny = rc.top;
        ncx = rc.right  - rc.left;
        ncy = rc.bottom - rc.top;
      }

      uStyle = WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
      uExStyle = WS_EX_TOPMOST;

      pszWindowTitle = TEXT("Screen Saver"); // MUST differ from preview

      // if there is another NORMAL screen save instance, switch to it
      hOther = FindWindow( pszWindowClass, pszWindowTitle );

      if( hOther && IsWindow( hOther ) )
      {
         SetForegroundWindow( hOther );
         return 0;
      }

      // Get current system power status and store it
      if (GetSystemPowerStatus(&sps)) {
        bACLineStatus = sps.ACLineStatus;
      }
      else {
        // we can't determine the power status, use default
        bACLineStatus = AC_LINE_UNKNOWN;
      }


      InitRealScreenSave();
   }

   //
   // the shell sends this message to the foreground window before running an
   // AutoPlay app. we return 1 to cancel autoplay if we are password protected
   //
   if (fOnWin95) {
        uShellAutoPlayQueryMessage = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
   } else {
        uShellAutoPlayQueryMessage = 0;
   }

   if( RegisterClass( &cls ) )
   {
      hMainWindow = CreateWindowEx( uExStyle, pszWindowClass, pszWindowTitle,
                        uStyle, nx, ny, ncx, ncy, hParent, (HMENU)NULL,
                        hMainInstance, (LPVOID)NULL );
   }

   msg.wParam = 0;
   if( hMainWindow )
   {
      if( !fChildPreview )
         SetForegroundWindow( hMainWindow );

      while( GetMessage( &msg, NULL, 0, 0 ) )
      {
         TranslateMessage( &msg );
         DispatchMessage( &msg );
      }
   }

   // free password-handling DLL if loaded
   UnloadPwdDLL();

   return msg.wParam;
}


//----------------------------------------------------------------------------

static INT_PTR
DoSaverPreview( LPCTSTR szUINTHandle )
{
   // get parent handle from string
   HWND hParent = (HWND)atoui( szUINTHandle );

   // only preview on a valid parent window (NOT full screen)
   return ( (hParent && IsWindow( hParent ))? DoScreenSave( hParent ) : -1 );
}


//----------------------------------------------------------------------------

static INT_PTR
DoConfigBox( HWND hParent )
{
   // let the consumer register any special controls for the dialog
   if( !RegisterDialogClasses( hMainInstance ) )
      return FALSE;

   return DialogBox( hMainInstance, MAKEINTRESOURCE( DLG_SCRNSAVECONFIGURE ),
                     hParent, (WNDPROC)ScreenSaverConfigureDialog );

}


//----------------------------------------------------------------------------

static INT_PTR
DoChangePw( LPCTSTR szUINTHandle )
{
   // get parent handle from string
   HWND hParent = (HWND)atoui( szUINTHandle );

   if( !hParent || !IsWindow( hParent ) )
      hParent = GetForegroundWindow();

   // allow the library to be hooked
   ScreenSaverChangePassword( hParent );
   return 0;
}

static const TCHAR szMprDll[] = TEXT("MPR.DLL");       // not to be localized
static const TCHAR szProviderName[] = TEXT("SCRSAVE"); // not to be localized

#ifdef UNICODE
static const CHAR szPwdChangePW[] = "PwdChangePasswordW"; // not to be localized
#else
static const CHAR szPwdChangePW[] = "PwdChangePasswordA"; // not to be localized
#endif

// bogus prototype
typedef DWORD (FAR PASCAL *PWCHGPROC)( LPCTSTR, HWND, DWORD, LPVOID );

void WINAPI
ScreenSaverChangePassword( HWND hParent )
{
   HINSTANCE mpr = LoadLibrary( szMprDll );

   if( mpr )
   {
      // netland hasn't cracked MNRENTRY yet
      PWCHGPROC pwd = (PWCHGPROC)GetProcAddress( mpr, szPwdChangePW );

      if( pwd )
         pwd( szProviderName, hParent, 0, NULL );

      FreeLibrary( mpr );
   }
}


//----------------------------------------------------------------------------

static BOOL
DoPasswordCheck( HWND hParent )
{
   // don't reenter and don't check when we've already decided
   if( fCheckingPassword || fClosing )
      return FALSE;

   if( VerifyPassword )
   {
      static DWORD lastcheck = (DWORD)-1;
      DWORD curtime = GetTickCount();
      MSG msg;

      if (dwPasswordDelay &&
         (GetElapsedTime(dwBlankTime, curtime) < dwPasswordDelay))
      {
         fClosing = TRUE;
         goto _didcheck;
      }

      // no rapid checking...
      if ((lastcheck != (DWORD)-1) &&
         (GetElapsedTime(lastcheck, curtime) < 200))
      {
         goto _didcheck;
      }

      // do the check
      fCheckingPassword = TRUE;

      // flush WM_TIMER messages before putting up the dialog
      PeekMessage( &msg, hParent, WM_TIMER, WM_TIMER, PM_REMOVE | PM_NOYIELD );
      PeekMessage( &msg, hParent, WM_TIMER, WM_TIMER, PM_REMOVE | PM_NOYIELD );

      // call the password verify proc
      fClosing = (BOOL)SendMessage( hParent, SCRM_VERIFYPW, 0, 0L );

      fCheckingPassword = FALSE;

      if (!fClosing)
         SetCursor(NULL);

      // curtime may be outdated by now
      lastcheck = GetTickCount();
   }
   else
   {
      // passwords disabled or unable to load handler DLL, always allow exit
      fClosing = TRUE;
   }

_didcheck:
   return fClosing;
}

//----------------------------------------------------------------------------
// stolen from the CRT, used to shirink our code

int _stdcall
DummyEntry( void )
{
    int i;
    STARTUPINFO si;
    LPTSTR pszCmdLine = GetCommandLine();

    if ( *pszCmdLine == TEXT('\"')) {
        /*
         * Scan, and skip over, subsequent characters until
         * another double-quote or a null is encountered.
         */
        while (*(pszCmdLine = CharNext(pszCmdLine)) &&
              (*pszCmdLine != TEXT('\"')) );
        /*
         * If we stopped on a double-quote (usual case), skip
         * over it.
         */
        if ( *pszCmdLine == TEXT('\"') )
            pszCmdLine++;
    }
    else {
        while ((UINT)*pszCmdLine > (UINT)TEXT(' '))
            pszCmdLine = CharNext(pszCmdLine);
    }

    /*
     * Skip past any white space preceeding the second token.
     */
    while (*pszCmdLine && ((UINT)*pszCmdLine <= (UINT)TEXT(' '))) {
        pszCmdLine = CharNext(pszCmdLine);
    }

    si.dwFlags = 0;
    GetStartupInfo(&si);

    i = (int)WinMainN(GetModuleHandle(NULL), NULL, pszCmdLine,
        si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);

    ExitProcess(i);
    return i;   // We never comes here.
}

//----------------------------------------------------------------------------
// main() entry point to satisfy old NT screen savers
void _cdecl main( int argc, char *argv[] ) {
    DummyEntry();
}

//----------------------------------------------------------------------------
// WinMain() entry point to satisfy old NT screen savers
int PASCAL WinMain( HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow ) {
    DummyEntry();
    return 0;

    // reference unreferenced parameters
    (void)hInst;
    (void)hPrev;
    (void)szCmdLine;
    (void)nCmdShow;
}


VOID LoadPwdDLL(VOID)
{
    HKEY hKey;

    if (!fOnWin95)
        return;

    if (hInstPwdDLL)
        UnloadPwdDLL();

    // look in registry to see if password turned on, otherwise don't
    // bother to load password handler DLL
    if (RegOpenKey(HKEY_CURRENT_USER,szScreenSaverKey,&hKey) ==
        ERROR_SUCCESS)
    {
        DWORD dwVal,dwSize=sizeof(dwVal);

        if ((RegQueryValueEx(hKey,szPasswordActiveValue,
            NULL,NULL,(BYTE *) &dwVal,&dwSize) == ERROR_SUCCESS)
            && dwVal)
        {

            // try to load the DLL that contains password proc.
            hInstPwdDLL = LoadLibrary(szPwdDLL);
            if (hInstPwdDLL)
            {
                VerifyPassword = (VERIFYPWDPROC) GetProcAddress(hInstPwdDLL,
                    szFnName);

                if( VerifyPassword )
                    HogMachine( TRUE );
                else
                    UnloadPwdDLL();
            }
        }

        RegCloseKey(hKey);
    }

}

VOID UnloadPwdDLL(VOID)
{
    if (!fOnWin95)
        return;

    if (hInstPwdDLL)
    {
        FreeLibrary(hInstPwdDLL);
        hInstPwdDLL = NULL;

        if( VerifyPassword )
        {
            VerifyPassword = NULL;
            HogMachine( FALSE );
        }
    }
}

//----------------------------------------------------------------------------
// compatbility stuff  (to make porting easier)
TCHAR szAppName[ APPNAMEBUFFERLEN ];
TCHAR szName[ TITLEBARNAMELEN ];
TCHAR szIniFile[ MAXFILELEN ];
TCHAR szScreenSaver[ 22 ];
TCHAR szHelpFile[ MAXFILELEN ];
TCHAR szNoHelpMemory[ BUFFLEN ];

// Quick fix for old screen savers that don't know about context
// sensitive help
UINT  MyHelpMessage = WM_HELP;