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 / Debugger / C++ Debugger / JDebug.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-10  |  17.7 KB  |  771 lines

  1. /*++
  2.  
  3. Copyright (c) 1996  Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.    jdebug.cpp
  8.  
  9. Abstract:
  10.  
  11.    Java debugger class implementation.
  12.  
  13.    The C++ debugger sample preforms the following steps:
  14.  
  15.     1) Connects to the debug manager.
  16.     2) Runs the Java debuggee applet.
  17.     3) Watches for the debuggee's Java VM to be created, and puts up a message box.
  18.     4) Connects to the debuggee's Java VM.
  19.     5) Watches for the debuggee class to be loaded.
  20.     6) Sets a breakpoint in a method in the debuggee class.
  21.     7) Watches for the breakpoint to be hit, and puts up a message box.
  22.     8) Clears the breakpoint.
  23.     9) Watches for the debuggee's Java VM to be destroyed, and puts up a message box.
  24.    10) Disconnects from the debuggee's Java VM.
  25.    11) Disconnects from the debug manager.
  26.    12) Exits.
  27.  
  28. --*/
  29.  
  30.  
  31. /* Headers
  32.  **********/
  33.  
  34. #include "project.hpp"
  35.  
  36. #include <javadbg.h>
  37. #include <jdbgguid.h>
  38.  
  39. #include "refcount.hpp"
  40.  
  41.  
  42. /* Classes
  43.  **********/
  44.  
  45. // sample Java debugger class
  46.  
  47. class JavaDebugger : public RefCount,
  48.                      public IRemoteDebugManagerCallback,
  49.                      public IRemoteProcessCallback
  50. {
  51. private:
  52.    /* Fields
  53.     *********/
  54.  
  55.    // debug manager
  56.    IRemoteDebugManager *m_pirdm;
  57.  
  58.    // remote process
  59.    IRemoteProcess *m_pirp;
  60.  
  61.    // debuggee class name
  62.    LPWSTR m_pwszDebugClass;
  63.  
  64.    /* Methods
  65.     **********/
  66.  
  67.    UINT RunMessageLoop(void);
  68.    void QuitMessageLoop(UINT uResult);
  69.  
  70. public:
  71.    /* Methods
  72.     **********/
  73.  
  74.    JavaDebugger(void);
  75.    ~JavaDebugger(void);
  76.    HRESULT Initialize(IRemoteDebugManager *pirdm);
  77.    void Terminate(void);
  78.    HRESULT Debug(LPCSTR pcszDebugClass);
  79.  
  80.    // IRemoteDebugManagerCallback methods
  81.  
  82.    HRESULT STDMETHODCALLTYPE ProcessCreateEvent(IRemoteProcess *pirpNew, IRemoteProcess *pirpParent);
  83.  
  84.    // IRemoteProcessCallback methods
  85.  
  86.    HRESULT STDMETHODCALLTYPE DebugStringEvent(IRemoteThread *pirth, LPCWSTR pcwszDebugMsg);
  87.    HRESULT STDMETHODCALLTYPE CodeBreakpointEvent(IRemoteThread *pirth);
  88.    HRESULT STDMETHODCALLTYPE DataBreakpointEvent(IRemoteThread *pirth, IRemoteObject *piro);
  89.    HRESULT STDMETHODCALLTYPE ExceptionEvent(IRemoteThread *pirth, IRemoteClassField *pircfException, EXCEPTIONKIND exk);
  90.    HRESULT STDMETHODCALLTYPE StepEvent(IRemoteThread *pirth);
  91.    HRESULT STDMETHODCALLTYPE CanStopEvent(IRemoteThread *pirth);
  92.    HRESULT STDMETHODCALLTYPE BreakEvent(IRemoteThread *pirth);
  93.    HRESULT STDMETHODCALLTYPE ThreadCreateEvent(IRemoteThread *pirth);
  94.    HRESULT STDMETHODCALLTYPE ThreadDestroyEvent(IRemoteThread *pirth);
  95.    HRESULT STDMETHODCALLTYPE ThreadGroupCreateEvent(IRemoteThread *pirth, IRemoteThreadGroup *pirthg);
  96.    HRESULT STDMETHODCALLTYPE ThreadGroupDestroyEvent(IRemoteThread *pirth, IRemoteThreadGroup *pirthg);
  97.    HRESULT STDMETHODCALLTYPE ClassLoadEvent(IRemoteThread *pirth, IRemoteClassField *pircfClass);
  98.    HRESULT STDMETHODCALLTYPE ClassUnloadEvent(IRemoteThread *pirth, IRemoteClassField *pircfClass);
  99.    HRESULT STDMETHODCALLTYPE ProcessDestroyEvent(IRemoteThread *pirth);
  100.    HRESULT STDMETHODCALLTYPE TraceEvent(IRemoteThread *pirth);
  101.    HRESULT STDMETHODCALLTYPE LoadCompleteEvent(IRemoteThread *pirth);
  102.  
  103.    // IUnknown methods
  104.  
  105.    DEFINE_DELEGATED_REFCOUNT_ADDREF(JavaDebugger);
  106.    DEFINE_DELEGATED_REFCOUNT_RELEASE(JavaDebugger);
  107.    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObject);
  108. };
  109.  
  110.  
  111. /* Module Constants
  112.  *******************/
  113.  
  114. #pragma data_seg(DATA_SEG_READ_ONLY)
  115.  
  116. const char SPACE                 = ' ';
  117. const char TAB                   = '\t';
  118. const char QUOTE                 = '\'';
  119. const char QUOTES                = '"';
  120.  
  121. const char s_cszMsgBoxTitle[]    = "Sample Java Debugger";
  122.  
  123. const char s_cszDebugClass[]     = "Hello";
  124. const WCHAR s_cwszDebugMethod[]  = L"main";
  125. const ULONG s_ulcBreakpointPC    = 0;
  126.  
  127. #pragma data_seg()
  128.  
  129.  
  130. /* Macros
  131.  *********/
  132.  
  133. //
  134. // Compile-time type check cast macro.
  135. //
  136. #define SAFE_CAST(type, obj) \
  137.    (((type)(obj) == (obj) ? 0 : 0), (type)(obj))
  138.  
  139. //
  140. // Safely delete an object.
  141. //
  142. #define SAFE_DELETE(ptr) \
  143.    { \
  144.       if (! (ptr)) \
  145.           ; \
  146.       else \
  147.       { \
  148.           delete(ptr); \
  149.           (ptr) = NULL;  \
  150.       } \
  151.    } \
  152.  
  153.  
  154. /***************************** Private Functions *****************************/
  155.  
  156.  
  157. //
  158. // Create a dynamically allocated Unicode copy of an ANSI string.
  159. //
  160. static HRESULT ANSIToUnicode(LPCSTR pcszANSI, LPWSTR *ppwszUnicode)
  161. {
  162.    HRESULT hr = E_UNEXPECTED;
  163.    int ncchANSI;
  164.    int ncchUnicode;
  165.  
  166.    // (+ 1) for null terminator.
  167.    ncchANSI = lstrlen(pcszANSI) + 1;
  168.  
  169.    ncchUnicode = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pcszANSI, ncchANSI, NULL, 0);
  170.  
  171.    if (ncchUnicode > 0)
  172.    {
  173.       *ppwszUnicode = new(WCHAR[ncchUnicode]);
  174.  
  175.       if (*ppwszUnicode)
  176.       {
  177.          if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pcszANSI, ncchANSI, *ppwszUnicode, ncchUnicode) == ncchUnicode)
  178.             hr = S_OK;
  179.          else
  180.          {
  181.             delete(*ppwszUnicode);
  182.             *ppwszUnicode = NULL;
  183.          }
  184.       }
  185.       else
  186.          hr = E_OUTOFMEMORY;
  187.    }
  188.    else
  189.       *ppwszUnicode = NULL;
  190.  
  191.    return(hr);
  192. }
  193.  
  194.  
  195. //
  196. // Skip over the white space at the beginning of a string.
  197. //
  198. LPCSTR SkipWhiteSpace(LPCSTR pcsz)
  199. {
  200.    while (*pcsz == SPACE ||
  201.           *pcsz == TAB)
  202.       pcsz = CharNext(pcsz);
  203.  
  204.    return(pcsz);
  205. }
  206.  
  207.  
  208. //
  209. // Skip over the meat at the beginning of a string.
  210. //
  211. static LPCSTR SkipNonWhiteSpace(LPCSTR pcsz)
  212. {
  213.    while (*pcsz &&
  214.           *pcsz != SPACE &&
  215.           *pcsz != TAB)
  216.       pcsz = CharNext(pcsz);
  217.  
  218.    return(pcsz);
  219. }
  220.  
  221.  
  222. //
  223. // Skip over a quoted substring at the beginning of a string.
  224. //
  225. static LPCSTR SkipQuotedArg(LPCSTR pcsz)
  226. {
  227.    char chQ;
  228.  
  229.    // Skip over quoted argument past matching quote.
  230.  
  231.    chQ = *pcsz;
  232.    pcsz = CharNext(pcsz);
  233.  
  234.    while (*pcsz &&
  235.           *pcsz != chQ)
  236.       pcsz = CharNext(pcsz);
  237.  
  238.    if (*pcsz == chQ)
  239.       pcsz = CharNext(pcsz);
  240.  
  241.    return(pcsz);
  242. }
  243.  
  244.  
  245. //
  246. // Skip over a possibly quoted substring at the beginning of a string.
  247. //
  248. static LPCSTR SkipPossiblyQuotedArg(LPCSTR pcsz)
  249. {
  250.    pcsz = SkipWhiteSpace(pcsz);
  251.  
  252.    switch (*pcsz)
  253.    {
  254.       case QUOTE:
  255.       case QUOTES:
  256.          pcsz = SkipQuotedArg(pcsz);
  257.          break;
  258.  
  259.       default:
  260.          pcsz = SkipNonWhiteSpace(pcsz);
  261.          break;
  262.    }
  263.  
  264.    return(pcsz);
  265. }
  266.  
  267.  
  268. //
  269. // Display a printf()-style message box.
  270. //
  271. static BOOL MyMessageBox(HWND hwndParent, UINT uStyle, LPCSTR pcszFormat, ...)
  272. {
  273.    char szMsg[1024];
  274.    va_list valArgs;
  275.  
  276.    // Lamely assume that wvsprintf() won't overflow szMsg[].
  277.  
  278.    va_start(valArgs, pcszFormat);
  279.    wvsprintf(szMsg, pcszFormat, valArgs);
  280.    va_end(valArgs);
  281.  
  282.    return(MessageBox(hwndParent, szMsg, s_cszMsgBoxTitle, uStyle));
  283. }
  284.  
  285.  
  286. /****************************** Public Functions *****************************/
  287.  
  288.  
  289. #pragma warning(disable:4100)    // "unreferenced formal parameter" warning
  290.  
  291. int __cdecl main(int argc, char *argv[])
  292. {
  293.    HRESULT hr;
  294.  
  295.    // Initialize OLE on this thread.
  296.  
  297.    hr = CoInitialize(NULL);
  298.  
  299.    if (SUCCEEDED(hr))
  300.    {
  301.        IRemoteDebugManager *pirdm;
  302.  
  303.        // Create a RemoteJavaDebugManager from JDbgMgr.exe to initiate debugging.
  304.  
  305.        hr = CoCreateInstance(CLSID_RemoteJavaDebugManager, NULL,
  306.                              CLSCTX_LOCAL_SERVER, IID_IRemoteDebugManager,
  307.                              (PVOID *)&pirdm);
  308.  
  309.        if (hr == S_OK)
  310.        {
  311.            JavaDebugger *pjd;
  312.  
  313.            // Create a JavaDebugger object to run a simple debugging session.
  314.  
  315.            pjd = new(JavaDebugger);
  316.  
  317.            if (pjd)
  318.            {
  319.                hr = pjd->Initialize(pirdm);
  320.  
  321.                if (hr == S_OK)
  322.                {
  323.                    hr = pjd->Debug(s_cszDebugClass);
  324.  
  325.                    pjd->Terminate();
  326.                }
  327.  
  328.                pjd->Release();
  329.                pjd = NULL;
  330.            }
  331.            else
  332.                hr = E_OUTOFMEMORY;
  333.  
  334.            pirdm->Release();
  335.            pirdm = NULL;
  336.        }
  337.  
  338.        // Uninitialize OLE on this thread.
  339.  
  340.        CoUninitialize();
  341.    }
  342.  
  343.    return(hr);
  344. }
  345.  
  346. #pragma warning(default:4100)    // "unreferenced formal parameter" warning
  347.  
  348.  
  349. /********************************** Methods **********************************/
  350.  
  351.  
  352. JavaDebugger::JavaDebugger(void)
  353. {
  354.    m_pirdm = NULL;
  355.    m_pirp = NULL;
  356.    m_pwszDebugClass = NULL;
  357.  
  358.    return;
  359. }
  360.  
  361.  
  362. JavaDebugger::~JavaDebugger(void)
  363. {
  364.    Terminate();
  365.  
  366.    return;
  367. }
  368.  
  369.  
  370. HRESULT JavaDebugger::Initialize(IRemoteDebugManager *pirdm)
  371. {
  372.    HRESULT hr;
  373.  
  374.    // Register this JavaDebugger's callback with the debug manager so it is notified when its debuggee target class is run.
  375.  
  376.    hr = pirdm->RegisterCallback(this);
  377.  
  378.    if (hr == S_OK)
  379.    {
  380.       m_pirdm = pirdm;
  381.       m_pirdm->AddRef();
  382.    }
  383.  
  384.    return(hr);
  385. }
  386.  
  387.  
  388. void JavaDebugger::Terminate(void)
  389. {
  390.    SAFE_DELETE(m_pwszDebugClass);
  391.  
  392.    return;
  393. }
  394.  
  395.  
  396. //
  397. // Run a message loop on this thread until a WM_QUIT message is encountered.
  398. //
  399. UINT JavaDebugger::RunMessageLoop(void)
  400. {
  401.    MSG msg;
  402.  
  403.    // No accelerators to load.
  404.  
  405.    // Get and dispatch messages until a WM_QUIT message is received.
  406.  
  407.    ZeroMemory(&msg, sizeof(msg));
  408.  
  409.    while (GetMessage(&msg, NULL, 0, 0))
  410.    {
  411.       // Translate virtual key codes.
  412.  
  413.       TranslateMessage(&msg);
  414.  
  415.       // Dispatch message to target window.
  416.  
  417.       DispatchMessage(&msg);
  418.    }
  419.  
  420.    return(msg.wParam);
  421. }
  422.  
  423.  
  424. //
  425. // Terminate any message loop running on this thread.
  426. //
  427. void JavaDebugger::QuitMessageLoop(UINT uResult)
  428. {
  429.    PostQuitMessage(uResult);
  430.  
  431.    return;
  432. }
  433.  
  434.  
  435. //
  436. // Initiate a simple debugging session.
  437. //
  438. HRESULT JavaDebugger::Debug(LPCSTR pcszDebugClass)
  439. {
  440.    HRESULT hr;
  441.  
  442.    // Remember the debuggee class name.
  443.  
  444.    SAFE_DELETE(m_pwszDebugClass);
  445.  
  446.    hr = ANSIToUnicode(pcszDebugClass, &m_pwszDebugClass);
  447.  
  448.    if (hr == S_OK)
  449.    {
  450.       LPCSTR pcszCmdLine;
  451.       STARTUPINFO si;
  452.       PROCESS_INFORMATION pi;
  453.  
  454.       // Treat our command line arguments as the command line to run the debuggee class.
  455.  
  456.       pcszCmdLine = SkipWhiteSpace(SkipPossiblyQuotedArg(GetCommandLine()));
  457.  
  458.       ZeroMemory(&si, sizeof(si));
  459.       si.cb = sizeof(si);
  460.  
  461.       // Start the debuggee class process suspended so we can get its process ID before it executes.
  462.  
  463.       hr = CreateProcess(NULL, (LPSTR)pcszCmdLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi) ? S_OK : E_FAIL;
  464.  
  465.       if (hr == S_OK)
  466.       {
  467.          HRESULT hrResume;
  468.  
  469.          // Ask the debug manager to notify us when the debuggee class is run.
  470.  
  471.          hr = m_pirdm->RequestCreateEvent(m_pwszDebugClass, pi.dwProcessId);
  472.  
  473.          // Resume the debuggee class process to begin debugging.
  474.  
  475.          hrResume = (ResumeThread(pi.hThread) != 0xffffffff) ? S_OK : E_FAIL;
  476.  
  477.          if (hr == S_OK)
  478.             hr = hrResume;
  479.  
  480.          CloseHandle(pi.hProcess);
  481.          CloseHandle(pi.hThread);
  482.  
  483.          // Run a message loop to dispatch OLE RPC messages.
  484.  
  485.          RunMessageLoop();
  486.       }
  487.    }
  488.  
  489.    return(hr);
  490. }
  491.  
  492.  
  493. HRESULT STDMETHODCALLTYPE JavaDebugger::QueryInterface(REFIID riid,
  494.                                                        PVOID *ppvObject)
  495. {
  496.     HRESULT hr = S_OK;
  497.  
  498.     if (riid == IID_IRemoteDebugManagerCallback)
  499.        *ppvObject = SAFE_CAST(IRemoteDebugManagerCallback *, this);
  500.     else if (riid == IID_IRemoteProcessCallback)
  501.        *ppvObject = SAFE_CAST(IRemoteProcessCallback *, this);
  502.     else if (riid == IID_IUnknown)
  503.        *ppvObject = SAFE_CAST(IUnknown *, (IRemoteDebugManagerCallback *)this);
  504.     else
  505.     {
  506.        *ppvObject = NULL;
  507.        hr = E_NOINTERFACE;
  508.     }
  509.  
  510.     if (hr == S_OK)
  511.         AddRef();
  512.  
  513.     return(hr);
  514. }
  515.  
  516.  
  517. //
  518. // Debugger event notification methods return an HRESULT as follows:
  519. //
  520. //      S_FALSE     Continue execution.
  521. //
  522. //      S_OK        Suspend execution of all threads in this VM until an
  523. //                  IRemoteThread method is called on this thread to resume
  524. //                  execution.
  525. //
  526. //      E_...       Error.
  527. //
  528.  
  529. #pragma warning(disable:4100)    // "unreferenced formal parameter" warning
  530.  
  531. HRESULT STDMETHODCALLTYPE JavaDebugger::ProcessCreateEvent(
  532.                                                     IRemoteProcess *pirpNew,
  533.                                                     IRemoteProcess *pirpParent)
  534. {
  535.    HRESULT hr;
  536.  
  537.    // Register this JavaDebugger's callback with the Java VM so it is notified when interesting events occur in the debuggee.
  538.  
  539.    hr = pirpNew->RegisterCallback(this);
  540.  
  541.    if (hr == S_OK)
  542.    {
  543.       m_pirp = pirpNew;
  544.       m_pirp->AddRef();
  545.    }
  546.  
  547.    MyMessageBox(NULL, (MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND), "Process created.");
  548.  
  549.    return(S_FALSE);
  550. }
  551.  
  552.  
  553. HRESULT STDMETHODCALLTYPE JavaDebugger::DebugStringEvent(IRemoteThread *pirth, LPCWSTR pcwszDebugMsg)
  554. {
  555.    return(S_FALSE);
  556. }
  557.  
  558.  
  559. HRESULT STDMETHODCALLTYPE JavaDebugger::CodeBreakpointEvent(IRemoteThread *pirth)
  560. {
  561.    HRESULT hr;
  562.    IRemoteStackFrame *pirsf;
  563.  
  564.    // Get the method object from the current thread's current stack frame.
  565.  
  566.    hr = pirth->GetCurrentFrame(&pirsf);
  567.  
  568.    if (hr == S_OK)
  569.    {
  570.       IRemoteContainerObject *pirco;
  571.  
  572.       hr = pirsf->GetMethodObject(&pirco);
  573.  
  574.       if (hr == S_OK)
  575.       {
  576.          IRemoteField *pirf;
  577.  
  578.          // Get the method field from the method object.
  579.  
  580.          hr = pirco->GetType(&pirf);
  581.  
  582.          if (hr == S_OK)
  583.          {
  584.             IRemoteMethodField *pirmf;
  585.  
  586.             hr = pirf->QueryInterface(IID_IRemoteMethodField, (PVOID *)&pirmf);
  587.  
  588.             if (hr == S_OK)
  589.             {
  590.                // Clear the breakpoint, and continue execution.
  591.  
  592.                hr = pirmf->ClearBreakpoint(s_ulcBreakpointPC);
  593.  
  594.                if (hr == S_OK)
  595.                   MyMessageBox(NULL, (MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND), "Hit breakpoint %ls.%ls().%lu.",
  596.                                m_pwszDebugClass,
  597.                                s_cwszDebugMethod,
  598.                                s_ulcBreakpointPC);
  599.  
  600.                pirmf->Release();
  601.                pirmf = NULL;
  602.             }
  603.  
  604.             pirf->Release();
  605.             pirf = NULL;
  606.          }
  607.  
  608.          pirco->Release();
  609.          pirco = NULL;
  610.       }
  611.  
  612.       pirsf->Release();
  613.       pirsf = NULL;
  614.    }
  615.  
  616.    return(S_FALSE);
  617. }
  618.  
  619.  
  620. HRESULT STDMETHODCALLTYPE JavaDebugger::DataBreakpointEvent(IRemoteThread *pirth, IRemoteObject *piro)
  621. {
  622.    return(S_FALSE);
  623. }
  624.  
  625.  
  626. HRESULT STDMETHODCALLTYPE JavaDebugger::ExceptionEvent(IRemoteThread *pirth, IRemoteClassField *pircfException, EXCEPTIONKIND exk)
  627. {
  628.    return(S_FALSE);
  629. }
  630.  
  631.  
  632. HRESULT STDMETHODCALLTYPE JavaDebugger::StepEvent(IRemoteThread *pirth)
  633. {
  634.    return(S_FALSE);
  635. }
  636.  
  637.  
  638. HRESULT STDMETHODCALLTYPE JavaDebugger::CanStopEvent(IRemoteThread *pirth)
  639. {
  640.    return(S_FALSE);
  641. }
  642.  
  643.  
  644. HRESULT STDMETHODCALLTYPE JavaDebugger::BreakEvent(IRemoteThread *pirth)
  645. {
  646.    return(S_FALSE);
  647. }
  648.  
  649.  
  650. HRESULT STDMETHODCALLTYPE JavaDebugger::ThreadCreateEvent(IRemoteThread *pirth)
  651. {
  652.    return(S_FALSE);
  653. }
  654.  
  655.  
  656. HRESULT STDMETHODCALLTYPE JavaDebugger::ThreadDestroyEvent(IRemoteThread *pirth)
  657. {
  658.    return(S_FALSE);
  659. }
  660.  
  661.  
  662. HRESULT STDMETHODCALLTYPE JavaDebugger::ThreadGroupCreateEvent(IRemoteThread *pirth, IRemoteThreadGroup *pirthg)
  663. {
  664.    return(S_FALSE);
  665. }
  666.  
  667.  
  668. HRESULT STDMETHODCALLTYPE JavaDebugger::ThreadGroupDestroyEvent(IRemoteThread *pirth, IRemoteThreadGroup *pirthg)
  669. {
  670.    return(S_FALSE);
  671. }
  672.  
  673.  
  674. HRESULT STDMETHODCALLTYPE JavaDebugger::ClassLoadEvent(IRemoteThread *pirth, IRemoteClassField *pircfClass)
  675. {
  676.    LPWSTR pwszClassName;
  677.  
  678.    // Get the name of the loaded class.
  679.  
  680.    if (pircfClass->GetName(&pwszClassName) == S_OK)
  681.    {
  682.       // Is this the class that a breakpoint is to be set in?
  683.  
  684.       if (! wcscmp(pwszClassName, m_pwszDebugClass))
  685.       {
  686.          IEnumRemoteField *pierf;
  687.  
  688.          // Yes.  Get the method field for the method to set a breakpoint in.
  689.  
  690.          if (pircfClass->GetFields(&pierf, FIELD_KIND_METHOD, 0, s_cwszDebugMethod) == S_OK)
  691.          {
  692.             IRemoteField *pirf;
  693.             ULONG ulcFetched;
  694.  
  695.             if (pierf->Next(1, &pirf, &ulcFetched) == S_OK)
  696.             {
  697.                IRemoteMethodField *pirmf;
  698.  
  699.                if (pirf->QueryInterface(IID_IRemoteMethodField, (PVOID *)&pirmf) == S_OK)
  700.                {
  701.                   // Set the breakpoint, and continue execution.
  702.  
  703.                   pirmf->SetBreakpoint(s_ulcBreakpointPC);
  704.  
  705.                   pirmf->Release();
  706.                   pirmf = NULL;
  707.                }
  708.  
  709.                pirf->Release();
  710.                pirf = NULL;
  711.             }
  712.  
  713.             pierf->Release();
  714.             pierf = NULL;
  715.          }
  716.       }
  717.  
  718.       CoTaskMemFree(pwszClassName);
  719.       pwszClassName = NULL;
  720.    }
  721.  
  722.    return(S_FALSE);
  723. }
  724.  
  725.  
  726. HRESULT STDMETHODCALLTYPE JavaDebugger::ClassUnloadEvent(IRemoteThread *pirth, IRemoteClassField *pircfClass)
  727. {
  728.    return(S_FALSE);
  729. }
  730.  
  731.  
  732. HRESULT STDMETHODCALLTYPE JavaDebugger::ProcessDestroyEvent(IRemoteThread *pirth)
  733. {
  734.    // Detach this JavaDebugger from the Java VM.
  735.  
  736.    m_pirp->Detach();
  737.  
  738.    m_pirp->Release();
  739.    m_pirp = NULL;
  740.  
  741.    // Detach this JavaDebugger from the debug manager.
  742.  
  743.    m_pirdm->Detach();
  744.  
  745.    m_pirdm->Release();
  746.    m_pirdm = NULL;
  747.  
  748.    MyMessageBox(NULL, (MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND), "Process destroyed.");
  749.  
  750.    // Quit the message loop, and end the debugging session.
  751.  
  752.    QuitMessageLoop(0);
  753.  
  754.    return(S_FALSE);
  755. }
  756.  
  757.  
  758. HRESULT STDMETHODCALLTYPE JavaDebugger::TraceEvent(IRemoteThread *pirth)
  759. {
  760.    return(S_FALSE);
  761. }
  762.  
  763.  
  764. HRESULT STDMETHODCALLTYPE JavaDebugger::LoadCompleteEvent(IRemoteThread *pirth)
  765. {
  766.    return(S_FALSE);
  767. }
  768.  
  769. #pragma warning(default:4100)    // "unreferenced formal parameter" warning
  770.  
  771.