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

📄 simpletapi.cpp

📁 DOS下采用中断接收数据的串口通讯的例子,很难找到的好东西!
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
//  SimpleTapi.cpp
//
//  Source code from:
//
//  Serial Communications: A C++ Developer's Guide, 2nd 
//  Edition by Mark Nelson, IDG Books, 1999
//
//  Please see the book for information on usage.
//
// This file contains the complete implementation of 
// the SimpleTapi class. SimpleTapi wraps up a limited
// subset of TAPI 1.4, using the SDK only for its modem
// control and call setup capabilities. This class
// contains several pure virtual functions that are needed
// for notification. Before you can use SimpleTapi, you will
// need to create a derived class that implements those
// functions. A simple example used in the book is
// MySimpleTapi, used in the Chapter 15 example.
//
#include "SimpleTapi.h"

//
// The static m_Trace object is shared by all extant 
// SimpleTapi devices. It provices a way to display trace
// messages. Calling the Open() and Close() method of this
// object will open and close a console window that displays 
// messages.
//

ConStream SimpleTapi::m_Trace;

//
// The SimpleTapi constructor has to do a couple of obvious 
// things, such as clearing the internal handles and setting
// up other variables. One of the things it does that isn't
// quite as obvious is to enumerate a list of modems that
// can be used with this class. That list is stored in the
// m_Devices vector, which is suitable for insertion into 
// a drop down list for selection by a user.
//

SimpleTapi::SimpleTapi()
{
    //
    // No line is active, no call is up
    //
    m_hLine = 0;
    m_hCall = 0;
    m_bCallHandleValid = false;
    DWORD version = TAPI_CURRENT_VERSION;
    //
    // Note that Microsoft categorizes this as an obsolete
    // function, but for a class like this that is only 
    // using TAPI for first part call control (setting up
    // and tearing down our own calls) it is entirely 
    // adequate. It registers our app and gets an app handle
    // in m_hLineApp, and lets TAPI know that we expect to
    // see all notification returned via our static function
    // SimpleTapi::CallBack()
    //
    DWORD device_count;
    LONG result = lineInitialize( &m_hLineApp,
                                  GetModuleHandle( NULL ),
                                  Callback,
                                  "TAPI Application",
                                  &device_count );
    m_Trace << "SimpleTapi::SimpleTapi() "
            << "lineInitialize() returned "
            << hex << result
            << dec << "\n";
    //
    // If error return, no devices, no app handle, not going
    // to do anything useful.
    //
    if ( result != 0 ) {
        device_count = 0;
        m_hLineApp = NULL;
    }
    //
    // We are going to add all data modems to the list of
    // useful devices. That list is a vector that contains
    // object of type TapiDevices, a little class used here
    // to hold a device name and tapi id. 
    //
    // One thing you see here in the call to lineGetDevCaps()
    // is a recurrent them in Microsoft SDKs. Instead of 
    // just telling us how much space we will need to get the
    // information, we're expected to make one call just 
    // to find out how much space is needed, then another
    // to get the actual data. I buck the system in this 
    // case by grossly overestimating the space needed and
    // attempting to do it all in one call.
    //
    m_Devices.resize( device_count );
    int j = 0;
    for ( int i = 0 ; i < (int) device_count ; i++ ) {
        char temp[ 4096 ];
        LINEDEVCAPS *dev_caps = (LINEDEVCAPS *) temp;
        dev_caps->dwTotalSize  = 4096;
        result = lineGetDevCaps( m_hLineApp,
                                 i,
                                 version,
                                 0,
                                 dev_caps );
        m_Trace << "SimpleTapi::SimpleTapi() "
                << "lineGetDevCaps("
                << i
                << ") returned "
                << hex
                << result
                << dec
                << "\n";
        //
        // To qualify as a useful device, I have to get
        // a successful return from lineGetDevCaps(), the
        // device has to be a data modem, and I have to have
        // a valid device name, as denoted by
        // dwLineNameOffset. If those conditions are met, I
        // add the device to the list of devices. Note that
        // the name is stored as a text string that may not
        // be null terminated. Fortunately there is a string
        // constructor that easily acommodates this.
        //
        if ( result == 0 &&
             dev_caps->dwLineNameOffset != 0 &&
             ( dev_caps->dwMediaModes & LINEMEDIAMODE_DATAMODEM ) )
        {
            m_Devices[ j ].m_sName
               = string( temp + dev_caps->dwLineNameOffset,
                         dev_caps->dwLineNameSize );
            m_Trace << "Device name = "
                    << m_Devices[ j ].m_sName
                    << "\n";
            m_Devices[ j++ ].m_iDeviceNumber = i;
        }
    }
    m_Devices.resize( j );
    m_ReplyAction = NOTHING;
    m_dwPendingReplyCode = -1;
}

//
// The destructor shuts down TAPI by calling lineShutdown, 
// passing the app handle. At that point the TAPI DLL may
// be unloaded and its internal resources given back to the
// system.
//
SimpleTapi::~SimpleTapi()
{
    LONG result = -1;
    if ( m_hLineApp != NULL )
        result = lineShutdown( m_hLineApp );
    m_Trace << "lineShutdown() result = "
            << hex
            << result 
            << dec
            << "\n";
}

//
// Many things that we ask TAPI to do take long amounts
// of time to accomplish. When we kick off one of these
// asynchronous events, our call to TAPI normally returns
// immediately. Later, as TAPI makes progress on our 
// request, it sends notification to us via this callback
// function.
//
// Unfortunately for C++ programmers, callback functions
// in Windows are C functions with no concept of a this 
// pointer. This means that the callback function has to
// be a static C++ member function. The good news is that
// TAPI makes provision for the callback function to carry
// around an untyped pointer that the user provides. In our
// case, that pointer is to a SimpleTapi object, giving us
// immediate access to the SimpleTapi object that is actually
// the source or target of the action.
//
void PASCAL SimpleTapi::Callback( DWORD hDevice,
                                  DWORD dwMsg,
                                  DWORD dwCallbackInstance,
                                  DWORD dwParam1,
                                  DWORD dwParam2,
                                  DWORD dwParam3 )
{
    SimpleTapi *tapi = (SimpleTapi *) dwCallbackInstance;
    //
    // Like most Windows callbacks, we have to examine the 
    // message type to decide what to do. SimpleTapi only
    // responds to two different message types: LINE_REPLY
    // and LINE_CALLSTATE. LINE_REPLY sends responses to
    // any of the three asynchronous commands: Make Call,
    // Drop Call, and Answer. LINE_CALLSTATE keeps us
    // up with the changes in a call state. It is where we
    // get the two important events used in the Chapter
    // 15 demo program, the connected and disconnected 
    // events.
    //
    switch ( dwMsg )
    {
    case LINE_REPLY :
        m_Trace << "LINE_REPLY, request = "
                   << hex 
                   << dwParam1
                   << ", result = "
                   << dwParam2
                   << dec
                   << "\n";
        //
        // If the user of this class made one of the three 
        // asynchronous function calls, it is presumably 
        // hanging around and waiting for an answer. We
        // supply the answer by calling one of the three
        // notification functions. These three notification
        // functions aren't defined in the base class, they
        // have to be implemented in a derived class that
        // is designed to work with a specific application.
        //
        // Note that in order for this section of code to
        // work, we need to only be waiting for one pending
        // action at a time. The pending action is stored
        // in the m_ReplyAction member of the object at the
        // time the asynchronous request is made, using an
        // enumerated type defined specifically in this 
        // class. We don't do anything with the result code
        // that TAPI passes in here, we just pass it along
        // to whoever is at the other end of the notification
        // call.
        //
        if ( dwParam1 == tapi->m_dwPendingReplyCode ) {
            switch ( tapi->m_ReplyAction ) {
            case NOTHING: 
                break;
            case HANDLE_MAKE_CALL_RESULT : 
                tapi->HandleMakeCallResult( dwParam2 ); 
                break;
            case HANDLE_DROP_RESULT      : 
                tapi->HandleDropResult( dwParam2 );     
                break;
            case HANDLE_ANSWER_RESULT    : 
                tapi->HandleAnswerResult( dwParam2 );
                break;
            }
            tapi->m_ReplyAction = NOTHING;
        }
        break;
    //
    // Things are really only interesting in TAPI while a 
    // call is in progress. When that is the case, we get
    // periodic updates from TAPI telling us how things are
    // going. As we progress through these actions, we 
    // generate notification function calls that allow the
    // owner of the TAPI object to do the appropriate things.
    // There is a general notification function that always
    // gets called, then specific notification routines for
    // the all important connected and disconnected events.
    //
    case LINE_CALLSTATE :
        tapi->NotifyCallStateChange( dwParam1 );
        //
        // if dwParam3 is non-zero for the LINE_CALLSATE
        // event, it is being used to inform us of our 
        // privilege state for the given line. For the type
        // of call control we are performing here, we should
        // always be the owner of the call.
        //
        switch ( dwParam3 ) {
		case LINECALLPRIVILEGE_OWNER :
			m_Trace << "SimpleTapi is now the owner of handle = "
                    << hex << hDevice
                    << dec << "\n";
			break;
		}
        //
        // When the LINE_CALLSTATE message is received, 
        // dwParam1 contains the new state of the call.
        // A few of these states are particularly exciting,
        // and lead to notification messages. Most of those
        // cases should be pretty obvious. The TAPI docs 
        // show a few more states than are shown here, and
        // a full-featured class might implement more
        // notification messages to deal with them. The ones
        // used here are adequate for a simple dialing and
        // connecting app.
        //
        switch ( dwParam1 ) {
            //
            // A connected state can occur after either side
            // decides to answer a call. The host app surely
            // needs to be notified by this callback routine.
            //
        case LINECALLSTATE_CONNECTED:
            tapi->ConnectedEvent();
            break;
        case LINECALLSTATE_IDLE:
        case LINECALLSTATE_DISCONNECTED:

⌨️ 快捷键说明

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