问题:
atl组件内可能有另外线程事件需要通知到html页面,采用调用js回调的方法解决,比如voip呼入弹屏等功能
解决:
网上许多同步方法,即从js调用atl接口-》atl接口再调用js回调,我称之为同步方法
百度了许久,终于找到异步线程调用方法,整理记录如下:
1、js设置回调
<OBJECT id=wcall align="CENTER" WIDTH=0 HEIGHT=0 classid="CLSID:****"></OBJECT>
<script language="javascript">
function initVoip()
{
var ok = wcall.Open(ip,port,user,pwd);
alert(ok);
wcall.YqSetCBK(0,onCallIn);
wcall.YqSetCBK(1,onCalling);
wcall.YqSetCBK(2,onOnHook);
wcall.YqSetCBK(3,onTransError);
}
function onCallIn(callid,callst,phone)
{
alert('callin:'+phone+',callid:'+callid+',callstatus:'+callst);
}
function onCalling(callid)
{
alert('calling:'+callid);
}
function onOnHook(callid)
{
alert('onhook:'+callid);
}
function onTransError(callid)
{
alert('transError:'+callid);
}
</script>
2、atl设置回调接口函数实现
static HRESULT myCoMarshalInterThreadInterfaceInStream(
REFIID riid,
LPUNKNOWN pUnk,
LPSTREAM * ppStm)
{
HRESULT hres;
hres = CreateStreamOnHGlobal(NULL, TRUE, ppStm);
if (FAILED(hres)) return hres;
hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG);
if (FAILED(hres))
{
(*ppStm)->Release();
*ppStm = NULL;
}
return hres;
}
STDMETHODIMP CCallInterface::YqSetCBK(LONG cbkType, VARIANT cbkJs)
{
// TODO: 在此添加实现代码
if (cbkType < CMDCNT && cbkType >= 0 && cbkJs.vt == VT_DISPATCH){
CmdInterface[cbkType].cmdType = (CMDTYPE)cbkType;
if (CmdInterface[cbkType].cmdDispatch != NULL){
IDispatch *tmp= CmdInterface[cbkType].cmdDispatch;
CmdInterface[cbkType].cmdDispatch = NULL;
tmp->Release();
}
CmdInterface[cbkType].cmdDispatch = cbkJs.pdispVal;
CmdInterface[cbkType].cmdDispatch->AddRef();
if(FAILED(myCoMarshalInterThreadInterfaceInStream(IID_IDispatch,CmdInterface[cbkType].cmdDispatch,&CmdInterface[cbkType].cmdStream)))
{
CmdInterface[cbkType].cmdDispatch->Release();
CmdInterface[cbkType].cmdDispatch = NULL;
return S_FALSE;
}
return S_OK;
}
return S_FALSE;
}
3、呼入时,呼叫线程调用接口回调
IDispatch *getAsyncCmdDisp()
{
ULARGE_INTEGER xpos;
LARGE_INTEGER seekto;
IDispatch *pDisp;
HRESULT hr;
if (cmdType == CMD_NONE || cmdType == CMD_MAX)
return NULL;
if(CmdInterface[cmdType].cmdStream == NULL || CmdInterface[cmdType].cmdDispatch == NULL)
return NULL;
memset(&seekto,0,sizeof(seekto));
CmdInterface[cmdType].cmdStream->Seek(seekto,STREAM_SEEK_SET,&xpos);
hr = CoUnmarshalInterface(CmdInterface[cmdType].cmdStream,IID_IDispatch,(void**)&pDisp);
if(FAILED(hr)){
LogFile->WriteLog("CoUnmarshalInterface error");
return NULL;
}
return pDisp;
}
void Async_doCallIng()
{
IDispatch* pDisp = getAsyncCmdDisp();
if (pDisp){
//_com_dispatch_raw_method参数:L"\x0003\x0003\x0008"参看VALTYPE的值定义,后面类似printf的变参
_com_dispatch_raw_method(pDisp,0,DISPATCH_METHOD,VT_EMPTY,NULL,L"\x0003",callId);
pDisp->Release();
}
}
void Async_doCallIn()
{
IDispatch* pDisp = getAsyncCmdDisp();
if (pDisp){
_com_dispatch_raw_method(pDisp,0,DISPATCH_METHOD,VT_EMPTY,NULL,L"\x0003\x0003\x0008",callId,callStatus,CComBSTR(callPhone));
pDisp->Release();
}
}
4、确实可以弹框,哈哈