工作问题总结(二十八)JS调用---网页调用C++程序,可传参

问题:怎样将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<>

{};


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值