2

I try use win32com.client.DispatchWithEvents for TAPI COM object

import win32com.client
class TapiEvents:
    pass

tapi = win32com.client.DispatchWithEvents("{21D6D48E-A88B-11D0-83DD-00AA003CCABD}",TapiEvents)

But it gives an error: This COM object does not support events.

Arty
  • 579
  • 1
  • 8
  • 17

2 Answers2

2

A working example looks like (working with CiscoTSP)

import win32com.client
cls="TAPI.TAPI.1"
# need for gen_py
ti = win32com.client.Dispatch(cls)._oleobj_.GetTypeInfo()
tlb, index = ti.GetContainingTypeLib()
tla = tlb.GetLibAttr()
win32com.client.gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4], bValidateFile=0)

class TapiEvents(win32com.client.getevents(cls)):
    def OnEvent(self, ev1,ev2): 
        print "OnEvent"

tapi=win32com.client.Dispatch(cls)
tapi.Initialize() # must run after Dispatch and before TapiEvents
events=TapiEvents(tapi)
tapi.EventFilter = 0x1FFFF

for addr in tapi.Addresses: 
    try:
        tapi.RegisterCallNotifications(addr,True,True,8,0)
    except:
        pass

import Tix
r=Tix.Tk()
r.mainloop()

For making call use

import win32com.client,time
tapi = win32com.client.Dispatch("TAPI.TAPI.1")
tapi.Initialize()
for item in tapi.Addresses: print item.AddressName
objCrtAddress = [item for item in tapi.Addresses if 'SEP' in item.AddressName][0]
sNumber='323'
gobjCall = objCrtAddress.CreateCall(sNumber, 1, 0x8)
gobjCall.Connect (False)
Arty
  • 579
  • 1
  • 8
  • 17
  • thanks so much for the example, this is the best I could find so far for using the TAPI in Python, do you have more hints for me how I can find out more like: How did you know that you have to set the tapi.EventFilter = 0x1FFFF to this value, which events do you filter with that? – select Feb 16 '15 at 16:49
  • 1
    I am very pleased that my example is useful. Thank You, @select. I had great difficulty finding the information. Example in python I have not found at all. Here are some links with examples in C ++, C # and VB, which helped me to understand (more VB). [tapi.info](http://www.tapi.info/default.aspx/TAPI/PSDKSamples.html) (example **calldemo.htm** helped me a lot) `tapi.EventFilter = 0x1FFFF` also in this example. [msdn](http://code.msdn.microsoft.com/TAPI-3-in-C-Get-Lines-and-dd143eaf) If you have any questions, tell me and I'll try to help. – Arty Feb 17 '15 at 19:40
0

While Arty's answer led the way for me, it's unfortunately at least by now both broken (probably due to using Python 2) and partial (e.g. displaying a literal "OnEvent" instead of event details, opening a whole menu (and thus getting broken on portable menu-less Python) without actually using it just for the sake of simulating an unofficial while loop, etc.).

I've therefore created my own version that:

  1. Works in Python v3.
  2. Displays every possible incoming call details (based on Tapi CALLINFO_STRING), but only if the data exists.
  3. Replaces TAPI.TAPI.1 with TAPI.TAPI to reduce changes to being obsolete.
  4. Actually uses a menu, but only if the the user decides so (print_console = True/False).
  5. Dials numbers by accepting a number as a command line parameter.
  6. Allowing to dial from all modems and alternatively displaying why all modems didn't match the requested one.

Don't forget to install pywin32 first.

Show incoming calls
(python callerid.py)

import pythoncom, time
import win32com.client
cls="TAPI.TAPI"
# need for gen_py
ti = win32com.client.Dispatch(cls)._oleobj_.GetTypeInfo()
tlb, index = ti.GetContainingTypeLib()
tla = tlb.GetLibAttr()
win32com.client.gencache.EnsureModule(tla[0], tla[1], tla[3], tla[4], bValidateFile=0)

print_console = False

class TapiEvents(win32com.client.getevents(cls)):
    def OnEvent(self, ev1,ev2): 
        constants = win32com.client.constants
        if ev1 == constants.TE_CALLNOTIFICATION:
            call = win32com.client.Dispatch(ev2).Call
            try:
               print_check_error(f"CIS_CALLEDIDNAME", call, constants.CIS_CALLEDIDNAME)
               print_check_error(f"CIS_CALLERIDNUMBER", call, constants.CIS_CALLERIDNUMBER)
               print_check_error(f"CIS_CALLEDIDNUMBER", call, constants.CIS_CALLEDIDNUMBER)
               print_check_error(f"CIS_CONNECTEDIDNAME", call, constants.CIS_CONNECTEDIDNAME)
               print_check_error(f"CIS_CONNECTEDIDNUMBER", call, constants.CIS_CONNECTEDIDNUMBER)
               print_check_error(f"CIS_REDIRECTIONIDNAME", call, constants.CIS_REDIRECTIONIDNAME)
               print_check_error(f"CIS_REDIRECTIONIDNUMBER", call, constants.CIS_REDIRECTIONIDNUMBER)
               print_check_error(f"CIS_REDIRECTINGIDNAME", call, constants.CIS_REDIRECTINGIDNAME)
               print_check_error(f"CIS_REDIRECTINGIDNUMBER", call, constants.CIS_REDIRECTINGIDNUMBER)
               print_check_error(f"CIS_CALLEDPARTYFRIENDLYNAME", call, constants.CIS_CALLEDPARTYFRIENDLYNAME)
               print_check_error(f"CIS_COMMENT", call, constants.CIS_COMMENT)
               print_check_error(f"CIS_DISPLAYABLEADDRESS", call, constants.CIS_DISPLAYABLEADDRESS)
               print_check_error(f"CIS_CALLINGPARTYID", call, constants.CIS_CALLINGPARTYID)
            except:
               pass

def print_check_error(str, obj, code):
   try:
    output = obj.CallInfoString(code)
    if bool(output):
       if print_console:
          print(f"{str}: {output}")
       else:
          update_text(f"{str}:\n{output}")
   except:
     pass

def update_text(str):
    label.config(text=str)

tapi=win32com.client.Dispatch(cls)
tapi.Initialize() # must run after Dispatch and before TapiEvents
events=TapiEvents(tapi)
tapi.EventFilter = 0x1FFFF

for addr in tapi.Addresses: 
    try:
        tapi.RegisterCallNotifications(addr,True,True,8,0)
    except:
        pass

if not print_console:
  try:
     import tkinter as tk
     r = tk.Tk()
     r.geometry(f"500x300+{int((r.winfo_screenwidth() / 2.5) - (r.winfo_reqwidth() / 2))}+{int((r.winfo_screenheight() / 2) - (r.winfo_reqheight() / 2))}")
     r.title("Incoming calls")
     label = tk.Label(r, text="Waiting for calls")
     label.pack()
     r.mainloop()
  except:
     print_console = True
     pass

if print_console:
  try:
     while True:
        pythoncom.PumpWaitingMessages()
        time.sleep(0.01)  # Don't use up all our CPU checking constantly
  except KeyboardInterrupt:
     pass

Dial numbers
(python call.py [enter number])

import sys
import win32com.client,time
tapi = win32com.client.Dispatch("TAPI.TAPI")
tapi.Initialize()
# for item in tapi.Addresses: print(item.AddressName)
modemAll = False
modem = "USB"

if len(sys.argv) > 1:
    sNumber = sys.argv[1]
else:
    exit("Send a phone number to the program")

found = False
modemList = []
for item in tapi.Addresses:
   if modemAll or modem in item.AddressName:
     found = True
     gobjCall = item.CreateCall(sNumber, 1, 0x8)
     gobjCall.Connect (False)
     if not modemAll:
        break
   else:
     modemList.append(item.AddressName)
if not found:
   modemList = str(modemList).strip('[]').replace(',', '\n')
   print(f"No modem matched {modem} in\n{modemList}")
LWC
  • 1,084
  • 1
  • 10
  • 28