问题:怎样将C++和js两者建立连接?
分为两个部分:
1.C++首先要建立适合自己的IDispatch类,IDispatch是com接口之一。下面是本人自己用的,大家如觉得有用,可借鉴。
ExternalAPI.h
#ifndef __EXTERNAL_API_H__
#define __EXTERNAL_API_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class ExternalAPIDispatch : public IDispatch
{
protected:
ULONG m_cRef;
public:
FastDelegate2<int,int> EnterRoom;
FastDelegate2<CString,CString> QQCertification;
FastDelegate2<CString,CString> SignupToGame;
FastDelegate2<CString,CString> CallSendSort;
FastDelegate2<CString,CString> CallCloseWebdlg;
FastDelegate2<CString,CString> CallOpenWebdlg;
FastDelegate2<CString,CString> CallMachineID;
FastDelegate2<CString,CString> CallShotBank;
FastDelegate2<CString,CString> RegUserInfo;
FastDelegate2<CString,CString> RegUserRestart;
FastDelegate2<CString,CString> RespGametoSignUp;
public:
ExternalAPIDispatch();
~ExternalAPIDispatch(void);
STDMETHODIMP QueryInterface(REFIID, void**);
STDMETHODIMP_(ULONG) AddRef(void);
STDMETHODIMP_(ULONG) Release(void);
//IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo);
STDMETHODIMP GetTypeInfo(
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ ITypeInfo** ppTInfo);
STDMETHODIMP GetIDsOfNames(
/* [in] */ REFIID riid,
/* [size_is][in] */ LPOLESTR* rgszNames,
/* [in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ DISPID* rgDispId);
STDMETHODIMP Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS* pDispParams,
/* [out] */ VARIANT* pVarResult,
/* [out] */ EXCEPINFO* pExcepInfo,
/* [out] */ UINT* puArgErr);
};
#endif //__EXTERNAL_API_H__
ExternalAPI.cpp
#include "stdafx.h"
#include "ExternalAPI.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#define DISPID_ENTERROOM 1
#define DISPID_QQCERTIFICATION 2
#define DISPID_SIGNUPTOGAME 3 //报名参加比赛
#define DISPID_CALLSENDSORT 4 //报名界面登陆后,网页调sort
#define DISPID_CALLCLOSEWEBDLG 5 //关闭绑定手机窗口
#define DISPID_OPENWEBDLG 7 //提供接口让网页判断,根据玩家状况打开相关的信息
#define DISPID_CALLMACHINEID 6
#define DISPID_CALLSHOTBANK 8 //截图银行窗口
#define DISPID_REGUSERINFO 9 //转正的个人信息
#define DISPID_REGUSERRESTART 10 //点击网页中重启
#define DISPID_RESPGAMETOSIGNUP 11 //游戏中点击报名下一场,是否报名成功返回
struct ExternalAPIKey
{
wchar_t *key;
long id;
};
ExternalAPIKey g_externalApiKey[] = {
{L"EnterRoom", DISPID_ENTERROOM },
{L"QQCertification",DISPID_QQCERTIFICATION},
{L"SignupToGame",DISPID_SIGNUPTOGAME},
{L"CallSendSort",DISPID_CALLSENDSORT},
{L"CallCloseWebdlg",DISPID_CALLCLOSEWEBDLG},
{L"CallOpenWebdlg",DISPID_OPENWEBDLG},
{L"CallMachineID",DISPID_CALLMACHINEID},
{L"CallShotBank",DISPID_CALLSHOTBANK},
{L"RegUserInfo",DISPID_REGUSERINFO},
{L"RegUserRestart",DISPID_REGUSERRESTART},
{L"RespGametoSignUp",DISPID_RESPGAMETOSIGNUP},
};
int getKeyFromID( wchar_t* key )
{
const int count = ARRAYSIZE(g_externalApiKey);
for(int i = 0; i < count ; i++){
if( wcscmp( g_externalApiKey[i].key, key ) == 0 ){
return g_externalApiKey[i].id;
}
}
return -1;
}
inline char* UnicodeToAnsi( const wchar_t* szStr )
{
int nLen = WideCharToMultiByte( CP_ACP, 0, szStr, -1, NULL, 0, NULL, NULL );
if (nLen == 0)
{
return NULL;
}
char* pResult = new char[nLen];
WideCharToMultiByte( CP_ACP, 0, szStr, -1, pResult, nLen, NULL, NULL );
return pResult;
}
ExternalAPIDispatch::ExternalAPIDispatch( )
:m_cRef( 0 )
{
}
ExternalAPIDispatch::~ExternalAPIDispatch(void)
{
ASSERT(m_cRef==0);
}
STDMETHODIMP ExternalAPIDispatch::QueryInterface(REFIID riid, void** ppv)
{
*ppv = NULL;
if(IID_IDispatch == riid){
*ppv = this;
}
if(NULL != *ppv){
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) ExternalAPIDispatch::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) ExternalAPIDispatch::Release(void)
{
return --m_cRef;
}
STDMETHODIMP ExternalAPIDispatch::GetTypeInfoCount(UINT* /*pctinfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP ExternalAPIDispatch::GetTypeInfo(
/* [in] */ UINT /*iTInfo*/,
/* [in] */ LCID /*lcid*/,
/* [out] */ ITypeInfo** /*ppTInfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP ExternalAPIDispatch::GetIDsOfNames(
/* [in] */ REFIID riid,
/* [size_is][in] */ OLECHAR** rgszNames,
/* [in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ DISPID* rgDispId)
{
HRESULT hr = NOERROR;
for(UINT i = 0; i < cNames; ++i )
{
long id = getKeyFromID( rgszNames[i]);
if( id > 0 ){
rgDispId[i] = id;
}else{
// One or more are unknown so set the return code accordingly
hr = ResultFromScode(DISP_E_UNKNOWNNAME);
rgDispId[i] = DISPID_UNKNOWN;
}
}
return hr;
}
STDMETHODIMP ExternalAPIDispatch::Invoke(
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID /*riid*/,
/* [in] */ LCID /*lcid*/,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS* pDispParams,
/* [out] */ VARIANT* pVarResult,
/* [out] */ EXCEPINFO* /*pExcepInfo*/,
/* [out] */ UINT* puArgErr)
{
//进入游戏
if( dispIdMember == DISPID_ENTERROOM ){
int gamdId = pDispParams->rgvarg[0].intVal;
int roomId = pDispParams->rgvarg[1].intVal;
if( EnterRoom ){
EnterRoom( gamdId, roomId );
}
}else if (dispIdMember == DISPID_QQCERTIFICATION)//QQ认证时,网页传出userid,sessionid
{
if (wFlags&DISPATCH_METHOD)
{
BSTR busername = pDispParams->rgvarg[1].bstrVal;
BSTR bsessionid = pDispParams->rgvarg[0].bstrVal;
CString musername = ::ConvertBSTRToStringEx(busername);
CString msessionid = ::ConvertBSTRToStringEx(bsessionid);
if (QQCertification)
{
QQCertification(musername,msessionid);
}
}
}else if (dispIdMember == DISPID_SIGNUPTOGAME)//点击报名按钮时,网页传递一个字符串通知大厅要上传比赛房间数据
{
//if(wFlags&DISPATCH_METHOD)
{
BSTR bflag = pDispParams->rgvarg[1].bstrVal;
BSTR bsignup = pDispParams->rgvarg[0].bstrVal;
CString strflag = ::ConvertBSTRToStringEx(bflag);
CString strSignup = ::ConvertBSTRToStringEx(bsignup);
if (SignupToGame)
{
SignupToGame(strflag,strSignup);
}
}
}else if (dispIdMember == DISPID_CALLSENDSORT)
{
BSTR bflag = pDispParams->rgvarg[1].bstrVal;
BSTR bsort = pDispParams->rgvarg[0].bstrVal;
CString strflag = ::ConvertBSTRToStringEx(bflag);
CString strSignup = ::ConvertBSTRToStringEx(bsort);
if (CallSendSort)
{
CallSendSort(strflag,strSignup);
}
}else if (dispIdMember == DISPID_CALLCLOSEWEBDLG)
{
BSTR bflag = pDispParams->rgvarg[1].bstrVal;
BSTR bClose = pDispParams->rgvarg[0].bstrVal;
CString strflag = ::ConvertBSTRToStringEx(bflag);
CString strclose = ::ConvertBSTRToStringEx(bClose);
if (CallCloseWebdlg)
{
CallCloseWebdlg(strflag,strclose);
}
}else if (dispIdMember == DISPID_OPENWEBDLG)
{
//LOG(ERROR)<<"DISPID_OPENWEBDLG";
BSTR bUrl = pDispParams->rgvarg[1].bstrVal;
BSTR bTitle = pDispParams->rgvarg[0].bstrVal;
CString strUrl = ::ConvertBSTRToStringEx(bUrl);
CString strTitle = ::ConvertBSTRToStringEx(bTitle);
if(CallOpenWebdlg)
{
CallOpenWebdlg(strTitle,strUrl);
}
}else if (dispIdMember == DISPID_CALLMACHINEID)
{
BSTR bMachineid = pDispParams->rgvarg[1].bstrVal;
BSTR bTrue = pDispParams->rgvarg[0].bstrVal;
CString strMachineid = ::ConvertBSTRToStringEx(bMachineid);
CString strTrue = ::ConvertBSTRToStringEx(bTrue);
if(CallMachineID)
{
CallMachineID(strTrue,strMachineid);
}
}else if (dispIdMember == DISPID_CALLSHOTBANK)
{
BSTR bBank = pDispParams->rgvarg[0].bstrVal;
BSTR bShotScreen = pDispParams->rgvarg[1].bstrVal;
CString strBank = ::ConvertBSTRToStringEx(bBank);
CString strShotScreen = ::ConvertBSTRToStringEx(bShotScreen);
if(CallShotBank)
{
CallShotBank(strShotScreen,strBank);
}
}else if (dispIdMember == DISPID_REGUSERINFO)
{
BSTR bUserName = pDispParams->rgvarg[1].bstrVal;
BSTR bUserPwd = pDispParams->rgvarg[0].bstrVal;
CString strUserName = ::ConvertBSTRToStringEx(bUserName);
CString strUserPwd = ::ConvertBSTRToStringEx(bUserPwd);
if (RegUserInfo)
{
RegUserInfo(strUserName,strUserPwd);
}
}else if (dispIdMember == DISPID_REGUSERRESTART)
{
BSTR bRestartLobby = pDispParams->rgvarg[1].bstrVal;
BSTR bTrue = pDispParams->rgvarg[0].bstrVal;
CString strRestartLobby = ::ConvertBSTRToStringEx(bRestartLobby);
CString strTrue = ::ConvertBSTRToStringEx(bTrue);
if (RegUserRestart)
{
RegUserRestart(strRestartLobby,strTrue);
}
}else if (dispIdMember == DISPID_RESPGAMETOSIGNUP)
{
BSTR bRespSignUp = pDispParams->rgvarg[1].bstrVal;
BSTR bTrue = pDispParams->rgvarg[0].bstrVal;
CString strRespSignUp = ::ConvertBSTRToStringEx(bRespSignUp);
CString strTrue = ::ConvertBSTRToStringEx(bTrue);
if (RespGametoSignUp)
{
RespGametoSignUp(strRespSignUp,strTrue);
}
}
return S_OK;
}
2.在C++程序中使用该接口
ExternalAPIDispatch m_externalAPI;
m_webCtrl.SetExternal(&m_externalAPI);
m_externalAPI.SignupToGame = MakeDelegate(this,&CompetitionRoomCtrl::JsCallSignupToGame);
m_externalAPI.CallSendSort = MakeDelegate(this,&CompetitionRoomCtrl::JsCallSendSort);
m_externalAPI.RespGametoSignUp = MakeDelegate(this,&CompetitionRoomCtrl::JsCallRespSignupToGame);
上面m_webCtrl是用来打开网页的窗口,CompetitionRoomCtrl窗口是要接收参数的窗口。CompetitionRoomCtrl::JsCallRespSignupToGame,这个是相应的接收函数。一一对应关系。
函数原型:
void CompetitionRoomCtrl::JsCallRespSignupToGame(CString strSignUp,CString strTrue)
{
//游戏中报名数据返回
if (0 == strSignUp.Compare("RESPSIGNUP")){
if(m_session){
m_session->SendRespSignUpInfoToGame(strSignUp,strTrue);
//LOG(ERROR)<<"JsCallRespSignupToGame("<<strSignUp<<","<<strTrue<<")";
}
}
}
大家再去看下上面的类中,参数个数与此函数的参数个数对应。
3.javascript上要添加的代码
具体代码没有,但是要告诉网站那边,相应接收参数的接口以及参数位置。比如:RegUserInfo(CString para1,CString para2)//参数1是登陆用户名,参数2是密码
(CString para1,CString para2)//参数1是登陆用户名,参数2是密码。
网页那边代码:window.external.RegUserInfo("GameQueen","123456");
上面的m_webCtrl这个窗口从下面类继承过来。
class WebCtrl : public CHtmlView,
public sigslot::has_slots<>
{};