home *** CD-ROM | disk | FTP | other *** search
/ Chip Special: HTML & Java / Chip-Special_1997-01_HTML-a-Java.bin / javasdk / sdk-java.exe / SDKJava.cab / Samples / JView / jview.cpp next >
Encoding:
C/C++ Source or Header  |  1996-10-10  |  27.6 KB  |  936 lines

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