TAPI 3 and C# -- Has anyone gotten it to work??

S

StevenVibert

I'm rewriting a C++ TAPI app I wrote a while ago in C#. Everything
works fine for the first call. Unfortunately, all subsequent calls are
completely ignored by TAPI until I restart the app again.

I remember running into this same problem with my original C++ code and
it was being caused by my failure to release all call related tapi
resources. As a point of reference the C++ app has been running quite
well for over a year.

Anyway, I beleive I'm releasing all the tapi interfaces when I'm done
with them but nothing I've done has solved the problem. I'm at a
complete loss as to what might be causing the problem. Any thoughts
would be greatly appreciated.

Here's the code:
========================

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using TAPI3Lib;

namespace CallManager
{
/// <summary>
/// Summary description for TapiMsgWindow.
/// </summary>
public class TapiMsgWindow : System.Windows.Forms.Form
{
public delegate void TapiInitializationDelegate(object sender, bool
success);
public event TapiInitializationDelegate TapiInitialization;

public delegate void CallNotificationDelegate(object sender);
public event CallNotificationDelegate CallNotification;

public delegate void CallStateDelegate(object sender,
TAPI3Lib.CALL_STATE callState);
public event CallStateDelegate CallState;

public delegate void CallInfoDelegate(object sender,
CALLINFOCHANGE_CAUSE cic);
public event CallInfoDelegate CallInfo;

public delegate void CallerIDEventDelegate(object sender,
CallerIDInfo cidInfo);
public event CallerIDEventDelegate CallerIDEvent;

public enum MEDIATYPE
{
MediaAudio = 8,
MediaModem = 16,
MediaFax = 32,
MediaVideo = 32768,
}

private MainForm _ParentForm = null;
private TAPI3Lib.TAPIClass _TAPI = null;
private ITAddress ListenAddress = null;
private ITBasicCallControl Call = null;
private int RegEventsResult = -1;
private int mediaTypes = 0;

private bool IsNewCall = false;
private int CurrentRingCount = 0;

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public TapiMsgWindow()
{
InitializeComponent();
}

public TapiMsgWindow(MainForm parentForm) : this()
{
_ParentForm = parentForm;
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
_TAPI.UnregisterNotifications(RegEventsResult);
_TAPI.Shutdown();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.Size = new System.Drawing.Size(300,300);
this.Text = "TapiMsgWindow";
}
#endregion

public bool InitTAPI()
{
bool result = false;
_TAPI = new TAPI3Lib.TAPIClass();

try
{
_TAPI.Initialize();
_TAPI.Event += new
ITTAPIDispatchEventNotification_EventEventHandler(OnTapiEvent);
result = SelectAddress();
}

catch(Exception ex)
{
MessageBox.Show(ex.Message);
result = false;
}

if(TapiInitialization != null)
TapiInitialization(this, result);

return result;
}

private bool SelectAddress()
{
bool result = false;
ITCollection addresses = (ITCollection)_TAPI.Addresses;
ITAddress curAddress = null;
ListenAddress = null;

//Careful here. The array is 1 based NOT 0 based;
for(int i = 1; i <= addresses.Count; i++)
{
curAddress = (ITAddress)addresses;

if(curAddress.State == ADDRESS_STATE.AS_INSERVICE)
{
ITMediaSupport mediaSupport = (ITMediaSupport)curAddress;

// Get the supported media types...
mediaTypes = mediaSupport.MediaTypes;
mediaSupport = null;

if((mediaTypes & (int)MEDIATYPE.MediaAudio) ==
(int)MEDIATYPE.MediaAudio)
{
ListenAddress = curAddress;
break;
}
}
}

// Did we find the address we were looking for?
if(ListenAddress != null)
{
RegEventsResult = _TAPI.RegisterCallNotifications(ListenAddress,
true, true, mediaTypes, 1);

_TAPI.EventFilter = (int)(
TAPI_EVENT.TE_CALLNOTIFICATION |
TAPI_EVENT.TE_CALLSTATE |
TAPI_EVENT.TE_DIGITEVENT |
TAPI_EVENT.TE_CALLINFOCHANGE |
TAPI_EVENT.TE_ADDRESS
);
}

else
{
MessageBox.Show("No TAPI address selected");
result = false;
}

result = true;
return result;
}

private void OnTapiEvent(TAPI_EVENT TapiEvent, object pEvent)
{
switch(TapiEvent)
{
case TAPI_EVENT.TE_CALLSTATE:
{
OnCallStateEvent((ITCallStateEvent)pEvent);
break;
}

case TAPI_EVENT.TE_ADDRESS:
{
OnAddressEvent((ITAddressEvent)pEvent);
break;
}

case TAPI_EVENT.TE_CALLNOTIFICATION:
{
OnCallNotifyEvent((ITCallNotificationEvent)pEvent);
break;
}

case TAPI_EVENT.TE_CALLINFOCHANGE:
{
OnCallInfoEvent((ITCallInfoChangeEvent)pEvent);
break;
}

case TAPI_EVENT.TE_PHONEEVENT:
{
Marshal.ReleaseComObject(pEvent);
break;
}

case TAPI_EVENT.TE_DIGITEVENT:
{
OnDigitEvent((ITDigitDetectionEvent)pEvent);
break;
}

case TAPI_EVENT.TE_GATHERDIGITS:
{
OnGatherDigits((ITDigitsGatheredEvent)pEvent);
break;
}

case TAPI_EVENT.TE_CALLMEDIA:
{
OnCallMediaChanged((ITCallMediaEvent)pEvent);
break;
}

case TAPI_EVENT.TE_TONEEVENT:
{
OnCallToneEvent((ITToneDetectionEvent)pEvent);
break;
}

default:
{
Marshal.ReleaseComObject(pEvent);
break;
}
}
}

private void OnCallInfoEvent(ITCallInfoChangeEvent pEvent)
{
Console.WriteLine("CallInfoEvent:");
Console.WriteLine(pEvent.Cause.ToString());

if(CallInfo != null)
CallInfo(this, pEvent.Cause);

try
{
if(pEvent.Cause == CALLINFOCHANGE_CAUSE.CIC_CALLERID)
{
if(CurrentRingCount >= 2)
{
string callerIDName =
pEvent.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNAME);
string callerIDNumber =
pEvent.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNUMBER);


CallerIDInfo cidInfo = new CallerIDInfo(callerIDNumber,
callerIDName);

if(CallerIDEvent != null)
CallerIDEvent(this, cidInfo);
}

}
}

catch(Exception ex)
{
MessageBox.Show(string.Format("CallInfoEvent failed with the
following exception:{0}", ex.Message));
}

finally
{
Marshal.ReleaseComObject(pEvent);
}
}

private void OnDigitEvent(ITDigitDetectionEvent pEvent)
{
try
{
byte digit = pEvent.Digit;
int digitMode = pEvent.DigitMode;
}

finally
{
Marshal.ReleaseComObject(pEvent);
}
}

private void OnGatherDigits(ITDigitsGatheredEvent pEvent)
{
try
{
}

finally
{
Marshal.ReleaseComObject(pEvent);
}
}

private void OnCallMediaChanged(ITCallMediaEvent pEvent)
{
try
{
}

finally
{
Marshal.ReleaseComObject(pEvent);
}
}

private void OnCallToneEvent(ITToneDetectionEvent pEvent)
{
try
{
}

finally
{
Marshal.ReleaseComObject(pEvent);
}
}

private void OnAddressEvent(ITAddressEvent pEvent)
{
ADDRESS_EVENT addressEvent = pEvent.Event;
Marshal.ReleaseComObject(pEvent);

switch(addressEvent)
{
case ADDRESS_EVENT.AE_RINGING:
{
CurrentRingCount++;
break;
}
}
}

private void OnCallNotifyEvent(ITCallNotificationEvent pEvent)
{
CALL_NOTIFICATION_EVENT callEvent = pEvent.Event;

if(Call != null)
{
Marshal.ReleaseComObject(Call);
Call = null;
}

Call = (ITBasicCallControl)(object)pEvent.Call;
IsNewCall = true;

Marshal.ReleaseComObject(pEvent);

switch(callEvent)
{
case CALL_NOTIFICATION_EVENT.CNE_MONITOR:
{
break;
}

case CALL_NOTIFICATION_EVENT.CNE_OWNER:
{
break;
}
}

if(CallNotification != null)
CallNotification(this);
}

private void OnCallStateEvent(ITCallStateEvent pEvent)
{
CALL_STATE state = pEvent.State;
Marshal.ReleaseComObject(pEvent);

if(CallState != null)
CallState(this, state);

switch(state)
{
case CALL_STATE.CS_IDLE:
{
break;
}

case CALL_STATE.CS_INPROGRESS:
{
break;
}
case CALL_STATE.CS_OFFERING:
{
break;
}

case CALL_STATE.CS_CONNECTED:
{
break;
}

case CALL_STATE.CS_QUEUED:
{
break;
}

case CALL_STATE.CS_HOLD:
{
break;
}

case CALL_STATE.CS_DISCONNECTED:
{
CurrentRingCount = 0;
DisconnectTheCall();
ReleaseTheCall();

IsNewCall = false;
break;
}
}
}

private void DisconnectTheCall()
{
Call.Disconnect(DISCONNECT_CODE.DC_NORMAL);
}

private void ReleaseTheCall()
{
Marshal.ReleaseComObject(Call);
Call = null;
}
}
}
 
S

StevenVibert

Well, I got it working by releasing TAPIClass and ITAddress objects and
re-initializing these objects after each call. It's working ok but
this seems a little strange that I would need to go to this extreme.

Thoughts, comments, and suggestions appreciated.

SteveV
 
S

StevenVibert

Thanks for the links. I had completely missed the MS kb article. I
had seen Helen's TAPI sample but it's TAPI2 and I was hoping to use my
existing TAPI3 c++ app as a model to minimize the amount of code
rewrite required to convert it to C#. Bummer.

Thanks again,
Steve
 
G

Guest

Steven
I'm using Tapi with C#. The difference is that i wrote a dll and call it by
C# (everythings, C# just call the functions).

Best regards,
Vuong
Tran xuan
 
G

Guest

Hi Steven,
I am starting my first steps in tapi using c #, i find it difficult but I
think your code gives me a good starting point.
Trying to run your code gave errors like :
* The type or namespace name 'MainForm' could not be found (are you missing
a using directive or an assembly reference?)
I tried to solve it by making new windows form of midi type with name
MainForm in namspace CallManger.
* The type or namespace name 'CallerIDInfo' could not be found (are you
missing a using directive or an assembly reference?)
Which i coul not find or solve.

So i will appreciate if you gave a hint how to make it work . or send me a
demo code.
It will be amazing to see working c# code for tapi Applications.
Thanks
Dr.Sameh Ali
(e-mail address removed)


I'm rewriting a C++ TAPI app I wrote a while ago in C#. Everything
works fine for the first call. Unfortunately, all subsequent calls are
completely ignored by TAPI until I restart the app again.

I remember running into this same problem with my original C++ code and
it was being caused by my failure to release all call related tapi
resources. As a point of reference the C++ app has been running quite
well for over a year.

Anyway, I beleive I'm releasing all the tapi interfaces when I'm done
with them but nothing I've done has solved the problem. I'm at a
complete loss as to what might be causing the problem. Any thoughts
would be greatly appreciated.

Here's the code:
========================

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using TAPI3Lib;

namespace CallManager
{
/// <summary>
/// Summary description for TapiMsgWindow.
/// </summary>
public class TapiMsgWindow : System.Windows.Forms.Form
{
public delegate void TapiInitializationDelegate(object sender, bool
success);
public event TapiInitializationDelegate TapiInitialization;

public delegate void CallNotificationDelegate(object sender);
public event CallNotificationDelegate CallNotification;

public delegate void CallStateDelegate(object sender,
TAPI3Lib.CALL_STATE callState);
public event CallStateDelegate CallState;

public delegate void CallInfoDelegate(object sender,
CALLINFOCHANGE_CAUSE cic);
public event CallInfoDelegate CallInfo;

public delegate void CallerIDEventDelegate(object sender,
CallerIDInfo cidInfo);
public event CallerIDEventDelegate CallerIDEvent;

public enum MEDIATYPE
{
MediaAudio = 8,
MediaModem = 16,
MediaFax = 32,
MediaVideo = 32768,
}

private MainForm _ParentForm = null;
private TAPI3Lib.TAPIClass _TAPI = null;
private ITAddress ListenAddress = null;
private ITBasicCallControl Call = null;
private int RegEventsResult = -1;
private int mediaTypes = 0;

private bool IsNewCall = false;
private int CurrentRingCount = 0;

/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public TapiMsgWindow()
{
InitializeComponent();
}

public TapiMsgWindow(MainForm parentForm) : this()
{
_ParentForm = parentForm;
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
_TAPI.UnregisterNotifications(RegEventsResult);
_TAPI.Shutdown();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.Size = new System.Drawing.Size(300,300);
this.Text = "TapiMsgWindow";
}
#endregion

public bool InitTAPI()
{
bool result = false;
_TAPI = new TAPI3Lib.TAPIClass();

try
{
_TAPI.Initialize();
_TAPI.Event += new
ITTAPIDispatchEventNotification_EventEventHandler(OnTapiEvent);
result = SelectAddress();
}

catch(Exception ex)
{
MessageBox.Show(ex.Message);
result = false;
}

if(TapiInitialization != null)
TapiInitialization(this, result);

return result;
}

private bool SelectAddress()
{
bool result = false;
ITCollection addresses = (ITCollection)_TAPI.Addresses;
ITAddress curAddress = null;
ListenAddress = null;

//Careful here. The array is 1 based NOT 0 based;
for(int i = 1; i <= addresses.Count; i++)
{
curAddress = (ITAddress)addresses;

if(curAddress.State == ADDRESS_STATE.AS_INSERVICE)
{
ITMediaSupport mediaSupport = (ITMediaSupport)curAddress;

// Get the supported media types...
mediaTypes = mediaSupport.MediaTypes;
mediaSupport = null;

if((mediaTypes & (int)MEDIATYPE.MediaAudio) ==
(int)MEDIATYPE.MediaAudio)
{
ListenAddress = curAddress;
break;
}
}
}

// Did we find the address we were looking for?
if(ListenAddress != null)
{
RegEventsResult = _TAPI.RegisterCallNotifications(ListenAddress,
true, true, mediaTypes, 1);

_TAPI.EventFilter = (int)(
TAPI_EVENT.TE_CALLNOTIFICATION |
TAPI_EVENT.TE_CALLSTATE |
TAPI_EVENT.TE_DIGITEVENT |
TAPI_EVENT.TE_CALLINFOCHANGE |
TAPI_EVENT.TE_ADDRESS
);
}

else
{
MessageBox.Show("No TAPI address selected");
result = false;
}

result = true;
return result;
}

private void OnTapiEvent(TAPI_EVENT TapiEvent, object pEvent)
{
switch(TapiEvent)
{
case TAPI_EVENT.TE_CALLSTATE:
{
OnCallStateEvent((ITCallStateEvent)pEvent);
break;
}

case TAPI_EVENT.TE_ADDRESS:
{
OnAddressEvent((ITAddressEvent)pEvent);
break;
}

case TAPI_EVENT.TE_CALLNOTIFICATION:
{
OnCallNotifyEvent((ITCallNotificationEvent)pEvent);
break;
}

case TAPI_EVENT.TE_CALLINFOCHANGE:
{
OnCallInfoEvent((ITCallInfoChangeEvent)pEvent);
break;
}

case TAPI_EVENT.TE_PHONEEVENT:
{
Marshal.ReleaseComObject(pEvent);
break;
}

case TAPI_EVENT.TE_DIGITEVENT:
{
OnDigitEvent((ITDigitDetectionEvent)pEvent);
break;
}

case TAPI_EVENT.TE_GATHERDIGITS:
{
OnGatherDigits((ITDigitsGatheredEvent)pEvent);
break;
}

case TAPI_EVENT.TE_CALLMEDIA:
{
OnCallMediaChanged((ITCallMediaEvent)pEvent);
break;
}

case TAPI_EVENT.TE_TONEEVENT:
{
OnCallToneEvent((ITToneDetectionEvent)pEvent);
break;
}

default:
{
Marshal.ReleaseComObject(pEvent);
break;
}
}
}

private void OnCallInfoEvent(ITCallInfoChangeEvent pEvent)
{
Console.WriteLine("CallInfoEvent:");
Console.WriteLine(pEvent.Cause.ToString());

if(CallInfo != null)
CallInfo(this, pEvent.Cause);

try
{
if(pEvent.Cause == CALLINFOCHANGE_CAUSE.CIC_CALLERID)
{
if(CurrentRingCount >= 2)
{
string callerIDName =
pEvent.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNAME);
string callerIDNumber =
pEvent.Call.get_CallInfoString(CALLINFO_STRING.CIS_CALLERIDNUMBER);


CallerIDInfo cidInfo = new CallerIDInfo(callerIDNumber,
callerIDName);

if(CallerIDEvent != null)
CallerIDEvent(this, cidInfo);
}

}
}

catch(Exception ex)
{
MessageBox.Show(string.Format("CallInfoEvent failed with the
following exception:{0}", ex.Message));
}

finally
{
Marshal.ReleaseComObject(pEvent);
}
 
G

Guest

hala dr. sameh

i quick-checked that code...mainform is just the parent form...and that
calledidinfo is just used for even triggereing as i understood...u can remove
them all and/or rewrite some parts of the code...

or just use/learn from my code in the other thread...

salam...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top