Platform SDK: TAPI

Hints and Tips

The following are points to consider when writing a TAPI 3.0 application.

  1. COM CoInitialize indirectly creates windows (especially important for apartment threading). If a thread creates any windows, it must process messages. So, if your threads call CoInitialize, you need to run a message pump to prevent problems from occurring. For example, COM might stop marshaling properly, or methods on COM interfaces such as IGlobalInterfaceTable might hang.

    In apartment threading you must have a message pump regardless of whether you wait for synchronization objects. This is particularly important if you have a console application or you write a COM local/remote server object that is apartment threaded (where you don't have a console or a GUI, but the control just "runs" in the system).

    Use caution when calling the wait and synchronization functions, such as Sleep(), WaitForMultipleObjects, WaitForMultipleObjectsEx, WaitForSingleObject, WaitForSingleObjectEx, and so on. Instead, use MsgWaitForMultipleObjects and process the messages, or use CoWaitForMultipleHandles(), which will automatically detect what type of apartment the thread is in (STA or MTA) and will wait either in COM's modal loop (if STA) or block on WaitForMultipleObjects (if MTA). MsgWaitForMultipleObjects and CoWaitForMultipleHandles() also process windows messages according to the COM rules.

    For example, instead of:

      Sleep (5000);  
    

    Use:

       {
       DWORD dwSignalled;
       HANDLE heventDone = CreateEvent(0, FALSE, FALSE, 0);
    
       CoWaitForMultipleHandles (COWAIT_ALERTABLE,
                             5000,
                             1,
                             &heventDone,
                             &dwSignalled);
    
       CloseHandle(heventDone);
       }
  2. ITTAPIEventNotification::Event is the apps Event routine that is called on TAPI3's callback thread. Look at Michelle Quinton's article in the November 1998 issue of Microsoft Journal for a good example of this. It uses the AddRef method to increase the reference count and does the actual processing on a separate thread. The more processing you do in the Event routine, the longer you block the TAPI callback thread and prevent other events from being sent.

    Do the minimum in the Event routine; instead, use one of your own threads where possible.

    HRESULT
    STDMETHODCALLTYPE
    CTAPIEventNotification::Event(
                                  TAPI_EVENT TapiEvent,
                                  IDispatch * pEvent
                                 )
    {
        //
        // addref the event so it doesn't go away
        //
        pEvent->AddRef();
    
        //
        // post a message to ourself
        //
        PostMessage(
                    ghDlg,
                    WM_PRIVATETAPIEVENT,
                    (WPARAM) TapiEvent,
                    (LPARAM) pEvent
                   );
    
        return S_OK;
    }
  3. CoUninitialize() Don't manipulate COM objects after calling CoUninitialize. The results are unpredictable and extremely detrimental to producing a healthy application. Some examples in which this can happen are worker threads and C++ destructors that may execute after your code calls CoUninitialize.