⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 freclien.txt

📁 服务器方面的
💻 TXT
📖 第 1 页 / 共 2 页
字号:
        else
        {
          // AddRef for the copy handed out to Thread1.
          m_pIBall->Release();

          // Create the Ball Moving Thread2.
          m_hBallThreads[1] = CreateThread(
                                0,
                                0,
                                (LPTHREAD_START_ROUTINE) BallThreadProc,
                                (LPVOID) &m_BallThreadData2,
                                0,
                                &m_dwBallThread2);

          bOk = (NULL != m_hBallThreads[1]);
          if (!bOk)
          {
            hr = GetLastError();
          }
          else
          {
            // AddRef for the copy handed out to Thread2.
            m_pIBall->Release();

            // Create the Ball Moving Thread3.
            m_hBallThreads[2] = CreateThread(
                                  0,
                                  0,
                                  (LPTHREAD_START_ROUTINE) BallThreadProc,
                                  (LPVOID) &m_BallThreadData3,
                                  0,
                                  &m_dwBallThread3);

            bOk = (NULL != m_hBallThreads[2]);
            if (!bOk)
            {
              hr = GetLastError();
            }
            else
            {
              // AddRef for the copy handed out to Thread3.
              m_pIBall->Release();
            }
          }
        }
      }
    }

    return (bOk);
  }

CoCreateInstance is called to create an instance of the FRESERVE server's
COBall object specified by its CLSID, CLSID_DllBall. This CLSID is defined
in BALLGUID.H, located in the sibling INC directory. Because aggregation
is not required, CoCreateInstance directly requests the IBall interface,
which on return is stored in m_pIBall. The Init method then launches the
three moving threads after setting appropriate CThreadInitData structures.
This is the CThreadInitData as declared in GUIBALL.H.

  // A small utility struct providing an encapsulation of data needed when
  // worker threads are initialized.
  struct CThreadInitData
  {
    HWND   m_hWnd;
    IBall* m_pIBall;
    DWORD  m_nDelay;
  };

As presented in the previous APTSERVE sample, a pointer to a
CThreadInitData structure is passed as an LPARAM to the thread procedure
of the newly launched thread. Using this structure, the client's main
window handle, an interface pointer to the IBall interface on the COBall
object, and a value for the time delay between ball movements are all
passed to the new threads. Following the COM contract, the Init method
calls m_pIBall->AddRef for each copy of the interface pointer returned to
the newly created thread. These AddRef calls are later matched by Release
calls in the CGuiBall destructor.

The m_hBallThreads array holds handles to the created threads. It is used
for later calls to WaitForMultipleObjects to ensure an orderly shutdown of
the threads before the client program exits. This occurs in the CGuiBall
destructor.  Here is the destructor from GUIBALL.CPP.

  CGuiBall::~CGuiBall(void)
  {
    BOOL bOk = TRUE;

    if (m_pIBall)
    {
      // Kill the client's app timer for its repaints.
      KillTimer(m_hWnd, 1);

      // Call down to the server's COBall and tell it to shutdown.
      m_pIBall->Move(FALSE);

      // Wait for the threads to terminate before closing their
      // thread handles.
      WaitForMultipleObjects(3, m_hBallThreads, TRUE, INFINITE);
      for (size_t i = 0; i<3; i++)
        CloseHandle(m_hBallThreads[i]);

      // Release for each of the thread copies handed out.
      RELEASE_INTERFACE(m_pIBall);
      RELEASE_INTERFACE(m_pIBall);
      RELEASE_INTERFACE(m_pIBall);
      // Release for the main copy held in CGuiBall.
      RELEASE_INTERFACE(m_pIBall);
    }
  }

The main process thread relies on a recurrent system timer's WM_TIMER
message. This was set up within the Init method of CGuiBall shown above.
These periodic timer messages drive the client's independent asynchronous
display process. The timer is killed in the destructor (see above) with
the KillTimer call. Each WM_TIMER message sent to the main window
procedure is honored by a call to the COBall::GetBall method to obtain the
ball's display data. Here is the main window procedure from FRECLIEN.CPP.

  LRESULT CMainWindow::WindowProc(
            UINT uMsg,
            WPARAM wParam,
            LPARAM lParam)
  {
    LRESULT lResult = FALSE;

    switch (uMsg)
    {
      case WM_CREATE:
        break;

      case WM_MEASUREITEM:
        // Get setup for painting text in this window.
        {
          LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
          lpmis->itemHeight = m_tm.tmHeight + m_tm.tmExternalLeading;
          lpmis->itemWidth = m_wWidth;
          lResult = TRUE;
        }

      case WM_SIZE:
        // Handle a resize of this window.
        m_wWidth = LOWORD(lParam);
        m_wHeight = HIWORD(lParam);
        // Handle a resize of this window.
        // Restart the ball from upper left, clear window.
        m_pGuiBall->Restart();
        break;

      case WM_TIMER:
        // This is our timed attempt to continuously paint the moving ball.
        // It doesn't move it. Other non-GUI threads move the virtual ball.
        m_pGuiBall->PaintBall();
        break;

      case WM_COMMAND:
        // Dispatch and handle any Menu command messages received.
        lResult = DoMenu(wParam, lParam);
        break;

      case WM_CHAR:
        if (wParam == 0x1b)
        {
          // Exit this app if user hits ESC key.
          PostMessage(m_hWnd,WM_CLOSE,0,0);
          break;
        }
      case WM_LBUTTONUP:
      case WM_PAINT:
        // If something major happened or user clicks or hits key then
        // repaint the whole window.
        m_pGuiBall->PaintWin();
        break;

      case WM_CLOSE:
        // The user selected Close on the main window's System menu.
      case WM_QUIT:
        // If the app is quit by the File/Exit main menu then close
        //   any associated help windows too.
        ::WinHelp(m_hWnd, m_szHelpFile, HELP_QUIT, 0);
      default:
        // Defer all messages NOT handled here to the Default Window Proc.
        lResult = ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
        break;
    }

    return(lResult);
  }

The CGuiBall::PaintBall method is called to paint the ball when the
WM_TIMER messages arrive. Other main client application messages of
interest are WM_SIZE, WM_PAINT, and WM_LBUTTONUP. For WM_SIZE, if the user
resizes the client application's main window, CGuiBall::Restart is called.
The WM_SIZE message handler calls COBall::Reset, which relocates the ball
to the upper left corner of the window and also resets the ball size. If
the user clicks the left mouse button (causing WM_LBUTTONUP) or a general
WM_PAINT condition occurs, the window is repainted, but the ball is not
reset.

The threads each run the following common thread procedure, BallThreadProc
in GUIBALL.CPP.

  DWORD WINAPI BallThreadProc(
                 LPARAM lparam)
  {
    CThreadInitData* pInitData = (CThreadInitData*) lparam;
    HRESULT hr;
    DWORD nEndCount = 0;
    BOOL bAlive = TRUE;
    DWORD nDelay;

    // Keep a copy here on the local stack of the ball move delay.
    nDelay = pInitData->m_nDelay;

    // Initialize COM for use by this thread. Tell COM we are
    // multi-threaded.
    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);

    // Continuously move the ball while it is still alive.
    while (bAlive)
    {
      // Use system timer to slow down the ball motion to the range
      // of the humanly perceptible.
      if (GetTickCount() > nEndCount)
      {
        // After the delay, call from this thread thru IBall interface to
        // move the single ball that lives in the COBall COM object.
        bAlive = pInitData->m_pIBall->Move(TRUE);

        // Set new timer end count.
        nEndCount = GetTickCount() + nDelay;
      }
    }

    // UnInitialize COM for use by this thread.
    CoUninitialize();

    return 0;
  }

Within each launched thread, COM is initialized specifying
COINIT_MULTITHREADED to indicate free threading. Each of the three threads
executes this same re-entrant thread procedure. Within the procedure, each
thread executes an indefinite while loop containing a call to the
IBall::Move method on the COBall object. Because these move calls would be
far too fast for human perception, each thread is kept busy in a delay
countdown using the system timer tick count. This sample uses delays in
the neighborhood of 100 milliseconds. When the delay is over, the Move
method is called on the COBall object. The three threads are running
concurrently and could make the Move calls at conflicting times. As
explained in the FRESERVE sample, the Move method on COBall is guarded by
the CThreaded OwnThis mechanism. If one of the threads currently owns the
COBall object, a Move call by another thread will block the calling thread
until it can obtain ownership.

Each thread's while loop terminates in BallThreadProc when the Move call
that is made there returns FALSE. This return signals that some other
thread had killed the ball by calling Move call with the bAlive parameter
set to FALSE. This terminating call is actually made by the main
application thread and not by any of the ball-moving threads. The call is
made in the CGuiBall destructor shown above. The destructor is run when
the main CGuiBall object is deleted because the user has closed or exited
the main application, causing an exit of the main process thread's message
loop in WinMain.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -