home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 14 / IOPROG_14.ISO / soft / sdkjava / sdkjava.exe / SDKJava.cab / Samples / JView / jview.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-05  |  34.6 KB  |  1,149 lines

  1. /*
  2.  * jview.cpp - JView front end, including command-line parsing logic.
  3.  *
  4.  * (C) Copyright 1996-1998, Microsoft Corporation and it suppliers.
  5.  */
  6.  
  7. #pragma hdrstop
  8.  
  9. #include "jview.h"
  10. #include "javaprop.hpp"
  11.  
  12. // Macros
  13.  
  14. #define WIN32_ERROR_TO_HRESULT(err)    MAKE_SCODE(SEVERITY_ERROR, FACILITY_WIN32, (err))
  15.  
  16. #define WIN32_RESULT_TO_HRESULT(err)   ((err) == ERROR_SUCCESS ? S_OK : WIN32_ERROR_TO_HRESULT(err))
  17.  
  18. #define LAST_WIN32_ERROR_TO_HRESULT()  WIN32_RESULT_TO_HRESULT(GetLastError())
  19.  
  20. #define APPLETVIEWER "sun.applet.AppletViewer"
  21.  
  22. //------------------------------------------------------------------------------
  23. // LoadOemString
  24. //
  25. // Wrapper for the Win32 LoadString API that translates the string to the OEM
  26. // character set before returning it to the caller.
  27. //------------------------------------------------------------------------------
  28.  
  29. BOOL LoadOemString(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int
  30.     nBufferMax)
  31. {
  32.     BOOL fResult;
  33.  
  34.     fResult = LoadString(hInstance, uID, lpBuffer, nBufferMax);
  35.  
  36.     if (fResult)
  37.         CharToOem(lpBuffer, lpBuffer);
  38.  
  39.     return fResult;
  40. }
  41.  
  42. //------------------------------------------------------------------------------
  43. // CJView::CJView:
  44. //    Constructor
  45. //------------------------------------------------------------------------------
  46. CJView::CJView (int ac, char **av) : m_ac (ac), m_av (av)
  47. {
  48.     m_fApplet      = FALSE;
  49.     m_fPause       = FALSE;
  50.     m_fVerify      = FALSE;
  51.     m_pszClassPath = NULL;
  52.     m_pszAppend    = NULL;
  53.     m_pszPrepend   = NULL;
  54.     m_pszClassName = NULL;
  55.     m_ppszArgs     = NULL;
  56.     m_iArgs        = 0;
  57.     m_pJE          = NULL;
  58.     m_pProperties  = NULL;
  59. }
  60.  
  61. //------------------------------------------------------------------------------
  62. // CJView::~CJView:
  63. //    Destructor
  64. //------------------------------------------------------------------------------
  65. CJView::~CJView ()
  66. {
  67.     deleteSZ(m_pszClassPath);
  68.     deleteSZ(m_pszClassName);
  69.     deleteSZ(m_pszAppend);
  70.     deleteSZ(m_pszPrepend);
  71.  
  72.     if (m_ppszArgs)
  73.     {
  74.         INT n = 0;
  75.  
  76.         while (m_ppszArgs[n] != NULL)
  77.             delete [] m_ppszArgs[n++];
  78.         delete [] m_ppszArgs;
  79.     }
  80.  
  81.     if (m_pProperties)
  82.     {
  83.         m_pProperties->Release();
  84.         delete(m_pProperties);
  85.     }
  86.  
  87.     if (m_pJE)
  88.     {
  89.         m_pJE->Release();
  90.         CoUninitialize();
  91.     }
  92. }
  93.  
  94. //------------------------------------------------------------------------------
  95. // CJView::m_Pause:
  96. //
  97. // -p was given on the command line, and we have an error, thus we display
  98. // amessage to the user to press a key to terminate JView, thus allowing enough
  99. // time to read the message before JView termnates and the console it was
  100. // running in goes away if being executed from the IDE
  101. //
  102. // Returns: Nothing
  103. //------------------------------------------------------------------------------
  104. void CJView::m_Pause()
  105. {
  106.     CHAR szText[BUFSIZE];
  107.  
  108.     LoadOemString(NULL, IDS_PRESSANYKEY, szText, sizeof(szText));
  109.     fprintf(stderr, "%s", szText);
  110.     _getch();
  111. }
  112.  
  113. //------------------------------------------------------------------------------
  114. // CJView::m_FatalError:
  115. //
  116. // Print a formatted error message to stderr
  117. //
  118. // Returns: Nothing
  119. //------------------------------------------------------------------------------
  120. void CJView::m_FatalError
  121. (
  122.     INT idString,
  123.     ...
  124. )
  125. {
  126.     CHAR szFmt[BUFSIZE];
  127.     va_list va;
  128.     va_start(va, idString);
  129.  
  130.  
  131.     LoadOemString(NULL, IDS_ERROR, szFmt, sizeof(szFmt));
  132.     fprintf(stderr, szFmt);
  133.  
  134.     if (idString)
  135.         LoadOemString(NULL, idString, szFmt, sizeof(szFmt));
  136.     else
  137.         lstrcpy(szFmt, "%s");
  138.  
  139.     vfprintf(stderr, szFmt, va);
  140.     va_end(va);
  141.     fprintf(stderr, "\n");
  142.  
  143.     if (m_fPause)
  144.         m_Pause();
  145. }
  146.  
  147. //------------------------------------------------------------------------------
  148. // CJView::m_FatalErrorHR:
  149. //
  150. //      Print a formatted error followup by an hresult tp stderr
  151. //------------------------------------------------------------------------------
  152. void CJView::m_FatalErrorHR
  153. (
  154.     HRESULT hr,
  155.     INT     idString,
  156.     ...
  157. )
  158. {
  159.     CHAR  szFmt[BUFSIZE];
  160.     CHAR  buf[BUFSIZE];
  161.     DWORD res;
  162.     va_list va;
  163.     va_start(va, idString);
  164.  
  165.     LoadOemString(NULL, IDS_ERROR, szFmt, sizeof(szFmt));
  166.     fprintf(stderr, szFmt);
  167.     LoadOemString(NULL, idString, szFmt, sizeof(szFmt));
  168.     vfprintf(stderr, szFmt, va);
  169.     va_end(va);
  170.  
  171.     res = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  172.                         NULL,
  173.                         (DWORD)hr,
  174.                         LOCALE_SYSTEM_DEFAULT,
  175.                         buf,
  176.                         sizeof(buf),
  177.                         NULL);
  178.  
  179.     CHAR szNoMain[BUFSIZE] = "";
  180.  
  181.     if (!res)
  182.     {
  183.         CHAR szSCODE[BUFSIZE];
  184.  
  185.         LoadOemString(NULL, IDS_SCODE, szSCODE, sizeof(szSCODE));
  186.         sprintf(buf, szSCODE, (DWORD)hr);
  187.     }
  188.     else
  189.     {
  190.         // Convert ANSI string returned by FormatMessage to OEM.
  191.         CharToOem(buf, buf);
  192.  
  193.         // Now we check if the error is "Member not found", and if it is, we
  194.         // will append some additional info to the error message letting
  195.         // the user know it was main() that could not be found, since that
  196.         // is the only time this message should be generated.
  197.         if (hr == DISP_E_MEMBERNOTFOUND)
  198.         {
  199.             CHAR sz[BUFSIZE] = "";
  200.  
  201.             LoadOemString(NULL, IDS_NOMAIN, sz, sizeof(sz));
  202.             sprintf(szNoMain, sz, m_pszClassName, m_pszClassName);
  203.         }
  204.         else
  205.             *szNoMain = '\0';
  206.     }
  207.  
  208.     fprintf(stderr, ": %s\n", buf);
  209.     if (*szNoMain)
  210.         fprintf(stderr, "%s", szNoMain);
  211.  
  212.     if (m_fPause)
  213.         m_Pause();
  214. }
  215.  
  216. //------------------------------------------------------------------------------
  217. // CJView::m_InitComAndJava:
  218. //
  219. // Initializes COM and obtains the neccessary interfaces from the Java VM
  220. //
  221. // Returns: TRUE if successful, FALSE if not
  222. //------------------------------------------------------------------------------
  223. BOOL CJView::m_InitComAndJava ()
  224. {
  225.     HRESULT           hr   = E_UNEXPECTED;
  226.     IClassFactory    *pcf  = NULL;
  227.  
  228.     hr = CoInitialize(NULL);
  229.  
  230.     if (FAILED(hr))
  231.     {
  232.         m_FatalErrorHR(hr, IDS_COULDNOTINITOLE);
  233.     }
  234.     else
  235.     {
  236.         hr = CoGetClassObject(CLSID_JavaExecute,
  237.                               CLSCTX_INPROC_SERVER |
  238.                               CLSCTX_INPROC_HANDLER |
  239.                               CLSCTX_LOCAL_SERVER,
  240.                               NULL,
  241.                               IID_IClassFactory,
  242.                               (LPVOID*)(&pcf));
  243.         if (FAILED(hr))
  244.         {
  245.             m_FatalErrorHR(hr, IDS_JAVAVM);
  246.         }
  247.         else
  248.         {
  249.             hr = pcf->CreateInstance(NULL, IID_IJavaExecute, (LPVOID *)(&m_pJE));
  250.             if (FAILED(hr))
  251.             {
  252.                 m_pJE = NULL;
  253.                 m_FatalErrorHR(hr, IDS_CLASSLOADER);
  254.             }
  255.  
  256.             pcf->Release();
  257.         }
  258.  
  259.         if (NULL == m_pJE)
  260.             CoUninitialize();
  261.     }
  262.  
  263.     return (m_pJE != NULL);
  264. }
  265.  
  266. //------------------------------------------------------------------------------
  267. // CJView::MB2WC:
  268. //
  269. //   Converts the multibyte string to a UNICODE string, allocating space
  270. // for the destination string.
  271. //
  272. // Returns: Pointer to newly allocated and converted string, NULL if it fails
  273. //------------------------------------------------------------------------------
  274. LPWSTR CJView::m_MB2WC
  275. (
  276.     LPCSTR szAnsi,
  277.     int    cchAnsi
  278. )
  279. {
  280.    // First, determine size of converted string
  281.    //--------------------------------------------------------------------------
  282.    LPWSTR pwsz    = NULL;
  283.    int    cchWide = MultiByteToWideChar(0, 0, szAnsi, cchAnsi, NULL, 0) + 1;
  284.  
  285.    if (cchWide > 0)
  286.    {
  287.        // Got size so allocate the space and convert the string
  288.        //----------------------------------------------------------------------
  289.        if (pwsz = new WCHAR[cchWide])
  290.           MultiByteToWideChar(0, 0, szAnsi, cchAnsi, pwsz, cchWide);
  291.     }
  292.  
  293.    return pwsz;
  294. }
  295.  
  296. //------------------------------------------------------------------------------
  297. // CJView::m_WC2MB:
  298. //
  299. //   Converts the given UNICODE string to a multibyte string, allocating space
  300. // for the destination string.
  301. //
  302. // Returns: Pointer to newly allocated and converted string, NULL if it fails
  303. //------------------------------------------------------------------------------
  304. LPSTR CJView::m_WC2MB
  305. (
  306.    LPCWSTR pwsz,
  307.    int     cchWide
  308. )
  309. {
  310.    // First, determine size of converted string
  311.    //--------------------------------------------------------------------------
  312.    LPSTR psz     = NULL;
  313.    int   cchAnsi = WideCharToMultiByte(0, 0, pwsz, cchWide, NULL, 0, NULL, NULL);
  314.  
  315.    if (cchAnsi > 0)
  316.    {
  317.        // Got size so allocate the space and convert the string
  318.        //----------------------------------------------------------------------
  319.       if (psz = new CHAR[cchAnsi])
  320.           WideCharToMultiByte(0, 0, pwsz, cchWide, psz, cchAnsi, NULL, NULL);
  321.     }
  322.  
  323.     return psz;
  324. }
  325.  
  326.  
  327. //------------------------------------------------------------------------------
  328. // CJView::m_newSZ:
  329. //
  330. // Allocates the given string, generating OUT OF MEMORY if it fails
  331. //
  332. // Returns: LPSTR to allocated buffer if successful, NULL if not
  333. //------------------------------------------------------------------------------
  334. LPSTR CJView::m_newSZ
  335. (
  336.     int cBytes
  337. )
  338. {
  339.     LPSTR psz = new CHAR[cBytes + 1]; // +1 for \0
  340.  
  341.     if (!psz)
  342.         m_FatalError(IDS_OUTOFMEMORY);
  343.  
  344.     return psz;
  345. }
  346.  
  347. //------------------------------------------------------------------------------
  348. // CJView::m_AppendPathString
  349. //
  350. // Appends the given path the the other given path, allocating and freeing
  351. // as neccessary
  352. //
  353. // Returns: TRUE if successful, FALSE if not
  354. //------------------------------------------------------------------------------
  355. BOOL CJView::m_AppendPathString
  356. (
  357.     LPSTR *ppszPath,
  358.     LPSTR  pszAppend
  359. )
  360. {
  361.     LPSTR psz    = NULL;
  362.     BOOL  fSemi2 = *CharPrev(pszAppend, pszAppend + lstrlen(pszAppend)) != ';';
  363.  
  364.     if (*ppszPath)
  365.     {
  366.         // Been here before, so we append the given string to the given path
  367.         //----------------------------------------------------------------------
  368.         if (!(psz = m_newSZ(lstrlen(*ppszPath))))
  369.             return FALSE;
  370.  
  371.         lstrcpy(psz, *ppszPath);
  372.         deleteSZ(*ppszPath);
  373.  
  374.         BOOL fSemi1 = *CharPrev(psz, psz + lstrlen(psz)) != ';';
  375.  
  376.         if (!(*ppszPath = m_newSZ(lstrlen(psz) + lstrlen(pszAppend) + fSemi1 + fSemi2)))
  377.         {
  378.             deleteSZ(psz);
  379.             return FALSE;
  380.         }
  381.  
  382.         lstrcpy(*ppszPath, psz);
  383.  
  384.         // Add semi-colon between paths if original path did not have one
  385.         //----------------------------------------------------------------------
  386.         if (fSemi1)
  387.             lstrcat(*ppszPath, ";");
  388.  
  389.         lstrcat(*ppszPath, pszAppend);
  390.         deleteSZ(psz);
  391.     }
  392.     else
  393.     {
  394.         // First time here, so copy Append string into Path
  395.         //----------------------------------------------------------------------
  396.         if (!(*ppszPath = m_newSZ(lstrlen(pszAppend) + fSemi2)))
  397.             return FALSE;
  398.  
  399.         lstrcpy(*ppszPath , pszAppend);
  400.     }
  401.  
  402.     // Append final semi-colon if string being append does not have one
  403.     //--------------------------------------------------------------------------
  404.     if (fSemi2)
  405.         lstrcat(*ppszPath, ";");
  406.  
  407.     return TRUE;
  408. }
  409.  
  410. //------------------------------------------------------------------------------
  411. // CJView::m_DisplayUsage:
  412. //
  413. //  Displays the usage text for JView.exe
  414. //
  415. // Returns: Nothing
  416. //------------------------------------------------------------------------------
  417. VOID CJView::m_DisplayUsage ()
  418. {
  419.     // NOTE: All usage lines must be sequential String
  420.     //       IDS starting with IDS_USAGE1
  421.     CHAR sz[BUFSIZE];
  422.     INT  i = 0;
  423.  
  424.     m_DisplayBanner();
  425.  
  426.     while (TRUE)
  427.     {
  428.         LoadOemString(NULL, IDS_USAGE1 + (i++), sz, sizeof(sz));
  429.         if (*sz == '~')
  430.             break;
  431.         printf(sz);
  432.     }
  433. }
  434.  
  435. //------------------------------------------------------------------------------
  436. // CJView::m_ParseSwitches:
  437. //
  438. //  Parses off the switches portion of the command line
  439. //
  440. // Returns: TRUE if successful, FALSE if not
  441. //------------------------------------------------------------------------------
  442. BOOL CJView::m_ParseSwitches
  443. (
  444.     int *piArg
  445. )
  446. {
  447.     BOOL   fSuccess = TRUE;
  448.     BOOL   fReplace = m_pszClassPath != NULL;
  449.     LPSTR *ppsz;
  450.     LPSTR  psz;
  451.  
  452.     *piArg = 1;
  453.  
  454.     // We support both '-' and '/' switch designators
  455.     //--------------------------------------------------------------------------
  456.     while ((*piArg < m_ac) && ((m_av[*piArg][0] == '-') || (m_av[*piArg][0] == '/')))
  457.     {
  458.         psz = CharNext(m_av[*piArg]);
  459.         
  460.         // Check for the -D switch prior to CharLowering the switch string.
  461.  
  462.         if ( (*psz == 'D' || *psz == 'd') && (*(psz+1)==':') )
  463.         {
  464.             char *pszPropStr = psz+2;
  465.  
  466.             if ( *pszPropStr == '\0' )
  467.             {
  468.                 m_FatalError(IDS_INVALIDSWITCH, psz);
  469.                 fSuccess = FALSE;
  470.                 break;
  471.             }
  472.  
  473.             // If we don't already have a properties object, create one.
  474.             if ( !m_pProperties )
  475.             {
  476.                 m_pProperties = new(CEnumJAVAPROPERTY);
  477.  
  478.                 if (!m_pProperties)
  479.                 {
  480.                     m_FatalError(IDS_OUTOFMEMORY);
  481.                     fSuccess = FALSE;
  482.                     break;
  483.                 }
  484.             }
  485.  
  486.             // Add the property to the property enumerator.
  487.             m_pProperties->Add(psz+2);
  488.         }
  489.         else
  490.         {
  491.             // All other switches are case insensitive, so just knock 'em down to 
  492.             // lowercase here.
  493.  
  494.             CharLower(psz);
  495.     
  496.             // Check for usage switch first.  This is only valid as first switch
  497.             //----------------------------------------------------------------------
  498.             if (*piArg == 1 && lstrcmp(psz, "?") == 0)
  499.             {
  500.              m_DisplayUsage();
  501.                 fSuccess = FALSE;
  502.                 break;
  503.             }
  504.     
  505.             // Check for "run in sun.applet.AppletViewer switch" , -a
  506.             if (lstrcmp(psz, "a") == 0)
  507.                 m_fApplet = TRUE;
  508.             // Check for "pause after error switch" , -p
  509.             else if (lstrcmp(psz, "p") == 0)
  510.                 m_fPause = TRUE;
  511.             // Check for "verify all" switch, -v
  512.             else if (lstrcmp(psz, "v") == 0)
  513.                 m_fVerify = TRUE;
  514.             // Silently ignore the old "quiet" switch for compatibility with
  515.             // existing scripts.
  516.             else if (lstrcmp(psz, "q") == 0)
  517.                 ;
  518.             else
  519.             {
  520.                 // Check for classpath switches -cp, -cp:p, or -cp:a
  521.                 //------------------------------------------------------------------
  522.                 BOOL fAppend  = FALSE;
  523.                 BOOL fPrepend = FALSE;
  524.     
  525.                 if (           !lstrcmp(psz, "cp")    ||
  526.                    (fPrepend = !lstrcmp(psz, "cp:p")) ||
  527.                    (fAppend  = !lstrcmp(psz, "cp:a")))
  528.                 {
  529.                     // We have classpath switch, so check for path.  If not given,
  530.                     // i.e, we're out of arguments, it's a bogus command line
  531.                     //--------------------------------------------------------------
  532.                     if (++(*piArg) == m_ac ||
  533.                        (m_av[*piArg][0] == '-' || m_av[*piArg][0] == '/'))
  534.                     {
  535.                         // We're about to exit, so we don't have to worry about
  536.                         // losing information in the ANSI to OEM conversion.
  537.                         CharToOem(m_av[*piArg - 1], m_av[*piArg - 1]);
  538.     
  539.                         m_FatalError(IDS_NOPATHGIVEN, m_av[*piArg - 1]);
  540.                         fSuccess = FALSE;
  541.                         break;
  542.                     }
  543.     
  544.                     // If we are given a class path on the command line and we also
  545.                     // have a classpath from the environment variable CLASSPATH,
  546.                     // the one given on the command line instructs us to ignore the
  547.                     // environment variable, and we instead append/prepend other
  548.                     // paths to this one instead
  549.                     //--------------------------------------------------------------
  550.                     if (fReplace && !(fPrepend || fAppend))
  551.                     {
  552.                         deleteSZ(m_pszClassPath);
  553.                         fReplace = FALSE;
  554.                     }
  555.     
  556.                     ppsz = fPrepend ? &m_pszPrepend : (fAppend ? &m_pszAppend :
  557.                                                                  &m_pszClassPath);
  558.                     m_AppendPathString(ppsz, m_av[*piArg]);
  559.                 }
  560.                 else
  561.                 {
  562.                     // We're about to exit, so we don't have to worry about
  563.                     // losing information in the ANSI to OEM conversion.
  564.                     CharToOem(m_av[*piArg], m_av[*piArg]);
  565.     
  566.                     // Bogus switch!
  567.                     m_FatalError(IDS_INVALIDSWITCH, m_av[*piArg]);
  568.                     fSuccess = FALSE;
  569.                     break;
  570.                 }
  571.             }
  572.         }
  573.  
  574.         (*piArg)++;
  575.     }
  576.  
  577.     return fSuccess;
  578. }
  579.  
  580. //------------------------------------------------------------------------------
  581. // CJView::m_ParseParameters
  582. //
  583. // Parses off the remaining command line arguments following the class simply
  584. // copying them into a list of OLESTRS
  585. //
  586. // Returns: TRUE if successful, FALSE if not
  587. //------------------------------------------------------------------------------
  588. BOOL CJView::m_ParseParameters
  589. (
  590.     int iNext
  591. )
  592. {
  593.     // If applet or stand-alone, we need a values array
  594.     //--------------------------------------------------------------------------
  595.     m_iArgs = m_ac - iNext;
  596.  
  597.     m_ppszArgs = new LPOLESTR[m_iArgs + 1];
  598.     if (!m_ppszArgs)
  599.     {
  600.         m_FatalError(IDS_OUTOFMEMORY);
  601.         return FALSE;
  602.     }
  603.  
  604.     (m_ppszArgs)[0] = NULL; // Initially empty!
  605.  
  606.     // Now, run through the list of arguments and process
  607.     //--------------------------------------------------------------------------
  608.     int i;
  609.  
  610.     for (i = 0; i < m_iArgs; i++)
  611.     {
  612.         if (!((m_ppszArgs)[i] = m_MB2WC(m_av[iNext++])))
  613.             break;
  614.     }
  615.  
  616.     // If succesful, mark end of array
  617.     //--------------------------------------------------------------------------
  618.     if (i == m_iArgs)
  619.     {
  620.         (m_ppszArgs)[i] = NULL;
  621.     }
  622.     else
  623.     {
  624.         // Clean up if we fail
  625.         //----------------------------------------------------------------------
  626.         int n;
  627.  
  628.         for (n = 0; n < i; n++)
  629.             deleteSZ(m_ppszArgs[n]);
  630.         deleteSZ(m_ppszArgs);
  631.     }
  632.  
  633.     return (i == m_iArgs);
  634. }
  635.  
  636. //------------------------------------------------------------------------------
  637. // CJView::ParseCommandLine:
  638. //
  639. //  Parses the command line, which must be in the format:
  640. //
  641. //  JView [switches] ClassName [Parameters]
  642. //
  643. //  switches:   None          :  Invoke main()
  644. //              -a            :  Run as Applet
  645. //              -cp   <path>  :  Set CLASSPATH to <path.
  646. //              -cp:p <path>  :  Prepend <path> to CLASSPATH
  647. //              -cp:a <path>  :  Append  <path> to CLASSPATH
  648. //
  649. //  Classname:  Class file to run.  Valid previously compiled .JAVA file(s)
  650. //
  651. //  Parameters: Name=Value
  652. //
  653. //              if value contains spaces, value must be contained in double
  654. //              quotes
  655. //
  656. //              Name="Value contains spaces"
  657. //
  658. // Returns: TRUE if successful, FALSE if not
  659. //------------------------------------------------------------------------------
  660. BOOL CJView::ParseCommandLine ()
  661. {
  662.     // Must have at least one command line arguement of class name
  663.     // Argument 0 is JVIEW itself
  664.     //--------------------------------------------------------------------------
  665.     if (m_ac == 1)
  666.     {
  667.         m_DisplayUsage();
  668.         return FALSE;
  669.     }
  670.  
  671.     // Get current CLASSPATH from VM.  We start with this, and append, prepend,
  672.     // or replace it with what we find on the command line
  673.     //--------------------------------------------------------------------------
  674.     LPOLESTR psz = NULL;
  675.  
  676.     if (m_pszClassPath = new CHAR[1])
  677.         *m_pszClassPath = 0;
  678.  
  679.     // First thing we check for are switches, processing all arguments that
  680.     // begin with "-".
  681.     // NOTE: All switches must come before class name and parameters
  682.     //--------------------------------------------------------------------------
  683.     INT i;
  684.  
  685.     if (!m_ParseSwitches(&i))
  686.         return FALSE;
  687.  
  688.     // Next on the command line should be the class file to execute.  If no more
  689.     // arguments, it's a bogus command line
  690.     //--------------------------------------------------------------------------
  691.     BOOL fSuccess = TRUE;
  692.  
  693.     if (i == m_ac)
  694.     {
  695.         m_FatalError(IDS_NOCLASSGIVEN);
  696.         fSuccess = FALSE;
  697.     }
  698.     else
  699.     {
  700.         // OK, we have another argument, so whatever it is we simply treat it as
  701.         // the class file name and let the VM deal with verifying it.
  702.         //----------------------------------------------------------------------
  703.         if (m_pszClassName = m_newSZ(lstrlen(m_fApplet ? APPLETVIEWER : m_av[i])))
  704.         {
  705.             lstrcpy(m_pszClassName, m_fApplet ? APPLETVIEWER : m_av[i++]);
  706.  
  707.             // Finally, if we have any more arguments, they are all treated as
  708.             // parameters to be used by the class
  709.             //------------------------------------------------------------------
  710.             if (i < m_ac)
  711.                 fSuccess = m_ParseParameters(i);
  712.         }
  713.     }
  714.  
  715.     if (fSuccess)
  716.     {
  717.         // Build final path string
  718.         //----------------------------------------------------------------------
  719.         if (m_pszPrepend)
  720.         {
  721.             if (m_pszClassPath)
  722.                 m_AppendPathString(&m_pszPrepend, m_pszClassPath);
  723.             deleteSZ(m_pszClassPath);
  724.             m_pszClassPath = m_pszPrepend;
  725.             m_pszPrepend   = NULL;
  726.         }
  727.  
  728.         if (m_pszAppend)
  729.         {
  730.             if (m_pszClassPath)
  731.             {
  732.                 m_AppendPathString(&m_pszClassPath, m_pszAppend);
  733.                 deleteSZ(m_pszAppend);
  734.             }
  735.             else
  736.             {
  737.                 m_pszClassPath = m_pszAppend;
  738.                 m_pszAppend    = NULL;
  739.             }
  740.         }
  741.     }
  742.  
  743.     return fSuccess;
  744. }
  745.  
  746. //------------------------------------------------------------------------------
  747. // CJView::m_DisplayBanner:
  748. //
  749. //  Displays the banner for JView.exe
  750. //
  751. // Returns: Nothing
  752. //------------------------------------------------------------------------------
  753. VOID CJView::m_DisplayBanner ()
  754. {
  755.     // Get FileVersion info
  756.     //--------------------------------------------------------------------------
  757.     DWORD dwVer = 0;
  758.  
  759.     CHAR szFile[MAX_PATH];
  760.  
  761.     GetModuleFileName(NULL, szFile, sizeof(szFile));
  762.  
  763.     VS_FIXEDFILEINFO *lpInfo;
  764.     DWORD  dw;
  765.     DWORD  dwSize = GetFileVersionInfoSize(szFile, &dw);
  766.     LPVOID lpData = (LPVOID)new CHAR[dwSize];
  767.  
  768.     GetFileVersionInfo(szFile, 0, dwSize, lpData);
  769.  
  770.     // Get File Version and File Description
  771.     //--------------------------------------------------------------------------
  772.     UINT ui;
  773.     VerQueryValue (lpData, "\\", (LPVOID*)&lpInfo, &ui);
  774.  
  775.     CHAR sz[BUFSIZE];
  776.  
  777.     LoadOemString(NULL, IDS_BANNER1, sz, sizeof(sz));
  778.     printf(sz, HIWORD(lpInfo->dwFileVersionMS),
  779.                LOWORD(lpInfo->dwFileVersionMS),
  780.                LOWORD(lpInfo->dwFileVersionLS));
  781.     LoadOemString(NULL, IDS_BANNER2, sz, sizeof(sz));
  782.     printf(sz);
  783.  
  784.     delete lpData;
  785. }
  786.  
  787. //------------------------------------------------------------------------------
  788. // CJView::Initialize:
  789. //
  790. //  Performs initialization for CJView
  791. //
  792. // Returns: TRUE if successful, FALSE if not
  793. //------------------------------------------------------------------------------
  794. BOOL CJView::Initialize ()
  795. {
  796.    return m_InitComAndJava();
  797. }
  798.  
  799. //------------------------------------------------------------------------------
  800. // RunMessageLoop:
  801. //      Message pump for OLE
  802. //
  803. //------------------------------------------------------------------------------
  804. UINT RunMessageLoop(void)
  805. {
  806.     MSG msg;
  807.  
  808.     // No accelerators to load.  Get and dispatch messages until a WM_QUIT
  809.     // message is received.
  810.     ZeroMemory(&msg, sizeof(msg));
  811.  
  812.     msg.wParam = S_OK;
  813.  
  814.     while (GetMessage(&msg, NULL, 0, 0))
  815.       //
  816.       // Dispatch message to target window.
  817.       //
  818.       // We don't have any windows, so there are no window procedures that
  819.       // require TranslateMessage(&msg).
  820.       //
  821.       DispatchMessage(&msg);
  822.  
  823.     return(msg.wParam);
  824. }
  825.  
  826. //------------------------------------------------------------------------------
  827. // CJView::SetSystemProperties:
  828. //
  829. // Will inform the VM of any additional system properties that we want to
  830. // set.
  831.  
  832. HRESULT CJView::SetSystemProperties()
  833. {
  834.     HRESULT        hr;
  835.     IJavaExecute2 *pije2;
  836.  
  837.     // If no properties defined, bail.
  838.     if ( !m_pProperties )
  839.         return S_OK;
  840.  
  841.     // Query for the IJavaExecute2 interface off of the existing
  842.     // IJavaExecute interface.
  843.     if (m_pJE->QueryInterface(IID_IJavaExecute2, (LPVOID*)&pije2) == S_OK)
  844.     {
  845.         // We found IJavaExecute2, set the system properties.
  846.         hr = pije2->SetSystemProperties( (IEnumJAVAPROPERTY *)m_pProperties);
  847.         pije2->Release();
  848.     }
  849.     else
  850.     {
  851.         // If the QI failed, this current VM does not support IJavaExecute2
  852.         hr = E_FAIL;
  853.         m_FatalError(IDS_PROPSNOTSUPPORTED);
  854.     }
  855.  
  856.     return hr;
  857. }
  858.  
  859. //------------------------------------------------------------------------------
  860. // CJView::ExecuteClass:
  861. //
  862. //  Executes the given class file
  863. //
  864. // Returns: result of IJavaExecute::Execute
  865. //------------------------------------------------------------------------------
  866.  
  867. HRESULT CJView::ExecuteClass (LPERRORINFO *ppIErrorInfo)
  868. {
  869.     LPOLESTR        pszClassName;
  870.     LPOLESTR        pszClassPath;
  871.     JAVAEXECUTEINFO jei;
  872.  
  873.     pszClassName = m_MB2WC(m_pszClassName);
  874.     pszClassPath = m_MB2WC(m_pszClassPath);
  875.  
  876.     jei.cbSize       = sizeof(jei);
  877.     jei.dwFlags      = m_fVerify ? JEIF_VERIFYCLASSES : 0;
  878.     jei.pszClassName = pszClassName;
  879.     jei.rgszArgs     = (LPCOLESTR *)(m_ppszArgs);
  880.     jei.cArgs        = m_iArgs;
  881.     jei.pszClassPath = pszClassPath;
  882.  
  883.     HRESULT hr = m_pJE->Execute(&jei, ppIErrorInfo);
  884.  
  885.     deleteSZ(pszClassPath);
  886.     deleteSZ(pszClassName);
  887.     return hr;
  888. }
  889.  
  890.  
  891. //------------------------------------------------------------------------------
  892. // RunClassThread
  893. //
  894. //  Executes the given class file.  If not found, executes without .class
  895. //  extension, if it has it.
  896. //
  897. // Returns: 0 if successful, 1 if not
  898. //------------------------------------------------------------------------------
  899.  
  900. DWORD _stdcall RunClassThread
  901. (
  902.     PVOID pv
  903. )
  904. {
  905.     CJView* pJV     = (CJView*)pv;
  906.     int     iResult = 1;            // Assume failure.
  907.  
  908.     if (pJV->ParseCommandLine())
  909.     {
  910.         HRESULT hr;
  911.         LPERRORINFO     pIErrorInfo = NULL;
  912.  
  913.         // Check for prepended path
  914.  
  915.         int len = strlen(pJV->m_pszClassName);
  916.  
  917.         if (len > 2 && (pJV->m_pszClassName[1] == ':' || strchr(pJV->m_pszClassName,'\\') != NULL))
  918.         {
  919.             char *fullname = pJV->m_newSZ(MAX_PATH);
  920.             char *endofpath;
  921.  
  922.             if (GetFullPathName(pJV->m_pszClassName, MAX_PATH+1, fullname, &endofpath))
  923.             {
  924.                 // Convert to long filename, if needed
  925.  
  926.                 WIN32_FIND_DATA findinfo;
  927.                 HANDLE hfind;
  928.  
  929.                 hfind = FindFirstFile(fullname, &findinfo);
  930.  
  931.                 if (hfind == INVALID_HANDLE_VALUE)
  932.                 {
  933.                     // Try appending a .class extension
  934.  
  935.                     strcat(endofpath, ".class");
  936.  
  937.                     hfind = FindFirstFile(fullname, &findinfo);
  938.                 }
  939.  
  940.                 if (hfind != INVALID_HANDLE_VALUE)
  941.                 {
  942.                     // Split path from name
  943.  
  944.                     *(endofpath-1) = '\0';
  945.  
  946.                     // Create the real class name and update length
  947.  
  948.                     deleteSZ(pJV->m_pszClassName);
  949.                     len = lstrlen(findinfo.cFileName);
  950.                     pJV->m_pszClassName = pJV->m_newSZ(len);
  951.                     lstrcpy(pJV->m_pszClassName, findinfo.cFileName);
  952.  
  953.                     // Prepend to specified path
  954.  
  955.                     if (*pJV->m_pszClassPath == '\0')
  956.                     {
  957.                         deleteSZ(pJV->m_pszClassPath);
  958.                         pJV->m_pszClassPath = fullname;
  959.                     }
  960.                     else
  961.                     {
  962.                         pJV->m_AppendPathString(&fullname, pJV->m_pszClassPath);
  963.                         deleteSZ(pJV->m_pszClassPath);
  964.                         pJV->m_pszClassPath = fullname;
  965.                     }
  966.  
  967.                     FindClose(hfind);
  968.                 }
  969.             }
  970.  
  971.             // else let the vm deal with whatever was specified.
  972.         }
  973.  
  974.         // Check for .class extension.
  975.  
  976.         const char classext1[] = ".cla";
  977.         const int classext1len = sizeof(classext1)-1;
  978.         const char classext2[] = ".class";
  979.         const int classext2len = sizeof(classext2)-1;
  980.  
  981.         char *classnameext = NULL;
  982.  
  983.         if (len > classext1len)
  984.         {
  985.             char *ext = pJV->m_pszClassName+len-classext1len;
  986.  
  987.             if (_stricmp(ext, classext1) == 0)
  988.             {
  989.                 // Truncate at extension.
  990.  
  991.                 *ext = '\0';
  992.                 classnameext = ext;
  993.             }
  994.             else
  995.             {
  996.                 // Try the full extension.
  997.  
  998.                 ext -= classext2len-classext1len;
  999.  
  1000.                 if (_stricmp(ext, classext2) == 0)
  1001.                 {
  1002.                     *ext = '\0';
  1003.                     classnameext = ext;
  1004.                 }
  1005.             }
  1006.         }
  1007.  
  1008.         // Set any user defined system properties.
  1009.         hr = pJV->SetSystemProperties();
  1010.  
  1011.         if ( hr == S_OK )
  1012.         {
  1013.             hr = pJV->ExecuteClass(&pIErrorInfo);
  1014.  
  1015.             if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) && classnameext != NULL)
  1016.             {
  1017.                 // Try the 1 in a billion possibility that someone is trying
  1018.                 // to execute some class named 'class' in a package.  Of course,
  1019.                 // if someone has a class with the same name as the package, we
  1020.                 // hit it first above.
  1021.  
  1022.                 *classnameext = '.';
  1023.  
  1024.                 hr = pJV->ExecuteClass(&pIErrorInfo);
  1025.             }
  1026.  
  1027.             if (!SUCCEEDED(hr))
  1028.             {
  1029.                 // We're about to exit, so we don't have to worry about
  1030.                 // losing information in the ANSI to OEM conversion.
  1031.                 CharToOem(pJV->m_pszClassName, pJV->m_pszClassName);
  1032.  
  1033.                 // Most likely .class file did not exist
  1034.                 pJV->m_FatalErrorHR (hr, IDS_EXECUTINGCLASS, pJV->m_pszClassName);
  1035.                 iResult = 1;
  1036.             }
  1037.             else if (pIErrorInfo)
  1038.             {
  1039.                 // VM threw an exception while running the .class file.  We
  1040.                 // get the info via the returned IErrorInfo interface
  1041.                 BSTR bstrError = NULL;
  1042.  
  1043.                 if (SUCCEEDED(pIErrorInfo->GetDescription(&bstrError)))
  1044.                 {
  1045.                     LPSTR pszError = pJV->m_WC2MB(bstrError);
  1046.  
  1047.                     if (pszError)
  1048.                     {
  1049.                         CharToOem(pszError, pszError);
  1050.                         pJV->m_FatalError (0, pszError);
  1051.                         deleteSZ(pszError);
  1052.                     }
  1053.                     else
  1054.                         pJV->m_FatalError (IDS_UNKNOWNERROR);
  1055.  
  1056.                     SysFreeString(bstrError);
  1057.                 }
  1058.                 else
  1059.                     pJV->m_FatalError(IDS_UNKNOWNERROR);
  1060.  
  1061.                 iResult = 1;
  1062.  
  1063.                 pIErrorInfo->Release();
  1064.             }
  1065.             else
  1066.               // Success.
  1067.               iResult = 0;
  1068.         }
  1069.     }
  1070.  
  1071.     // Terminate message pump
  1072.     PostThreadMessage(pJV->m_dwMsgLoopThreadID, WM_QUIT, 0, 0);
  1073.  
  1074.     return (DWORD)iResult;
  1075. }
  1076.  
  1077. //------------------------------------------------------------------------------
  1078. // main() - Entry point for JView
  1079. //
  1080. // Returns: 0 if successful, 1 if not
  1081. //------------------------------------------------------------------------------
  1082.  
  1083. #ifdef NO_CONSOLE
  1084. #define ENTRYPOINT int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  1085. #else
  1086. #define ENTRYPOINT int __cdecl main( int, char ** )
  1087. #endif
  1088.  
  1089. ENTRYPOINT
  1090. {
  1091.     int     iRet = 1;
  1092.     CJView* pJV  = new CJView(__argc,__argv);
  1093.  
  1094.     if (!pJV)
  1095.     {
  1096.         CHAR szFmt[64];
  1097.  
  1098.         LoadOemString(NULL, IDS_ERROR, szFmt, sizeof(szFmt));
  1099.         fprintf(stderr, szFmt);
  1100.         LoadOemString(NULL, IDS_OUTOFMEMORY, szFmt, sizeof(szFmt));
  1101.         fprintf(stderr, szFmt);
  1102.         fprintf(stderr, "\n");
  1103.         return iRet;
  1104.     }
  1105.  
  1106.     if (pJV->Initialize())
  1107.     {
  1108.         // OK, we're ready, everything is done on the applet thread
  1109.         HANDLE hth;
  1110.         DWORD  dwThreadID;
  1111.  
  1112.         pJV->m_dwMsgLoopThreadID = GetCurrentThreadId();
  1113.         hth = CreateThread(NULL, 0, &RunClassThread, pJV, 0, &dwThreadID);
  1114.  
  1115.         if (hth)
  1116.         {
  1117.             RunMessageLoop();
  1118.  
  1119.                // If we returned from RunMessageLoop() as a result of
  1120.                // RunClassThread() posting the WM_QUIT message, then the thread
  1121.                // will be exiting shortly (if not already).  We wait for it to
  1122.                // terminate and grab its exit code.  1/2 second is plenty --
  1123.                // if the thread doesn't die by then, something is wrong (we
  1124.                // got a quit message from someone else, perhaps?) in which case
  1125.                // we return 1 for failure.
  1126.  
  1127.                if (WaitForSingleObject (hth, 500) == WAIT_OBJECT_0)
  1128.                {
  1129.                      DWORD   dwRetCode = 1;
  1130.  
  1131.                      // Thread's dead, baby... thread's dead...
  1132.                      GetExitCodeThread (hth, &dwRetCode);
  1133.                      iRet = dwRetCode;
  1134.                }
  1135.                CloseHandle(hth);
  1136.                hth = NULL;
  1137.         }
  1138.         else
  1139.         {
  1140.             pJV->m_FatalErrorHR(LAST_WIN32_ERROR_TO_HRESULT(),
  1141.                                 IDS_NOJAVATHREAD);
  1142.         }
  1143.     }
  1144.  
  1145.     delete pJV;
  1146.     return iRet;
  1147. }
  1148.  
  1149.