C++ Silverlight 主机与 Silverlight 应用程序之间的通信






4.67/5 (9投票s)
本文档解释了如何从 C++ Silverlight 主机调用在 Silverlight 中定义的方法。
引言
在继续阅读本文之前,请先阅读我的上一篇文章 Host_Silverlight_In_ATL。 在本文中,我们将讨论 C++ Silverlight 主机和 Silverlight 应用程序之间的通信,这意味着我们可以从 C++ Silverlight 主机调用 Silverlight 应用程序的方法。

在 Silverlight 应用程序中需要做的事情
using System.Windows.Browser;
使用上述命名空间进行通信。 我们将使用 HTML 通信桥与 C++ 主机进行通信。
使用以下语句注册 Communicator 对象。 我们将通过 IDispath
在 C++ Silverlight 主机中获取此 communicator 对象。
HtmlPage.RegisterScriptableObject("Communicator", this);
在 Silverlight 应用程序中编写另一个函数,我们将从 C++ Silverlight 主机调用它。
[ScriptableMember]
public void SetDataInTextBox(string strData)
{
txtData.Text = strData;
}
Silverlight 页面的完整代码如下
using System.Windows.Browser;
namespace SilverlightTestApp
{
public partial class MainPage : UserControl
{
public MainPage()
{
HtmlPage.RegisterScriptableObject("Communicator", this);
InitializeComponent();
}
private void ClickMe_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button click handler is in Silverlight :)",
"SilverlightTestApp", MessageBoxButton.OK);
}
[ScriptableMember]
public void SetDataInTextBox(string strData)
{
txtData.Text = strData;
}
}
}
我这里不打算解释 Silverlight 开发问题,但我想说的是,我们对 Silverlight 和 JavaScript 的交互所做的事情是一样的。 如果您不熟悉上面的代码,请在 Google 上搜索 Silverlight 和 JavaScript 交互。 几乎每本书籍都会涵盖这个主题。
C++ Silverlight 主机
在 ATL 应用程序的对话框中添加一个编辑框和一个按钮。 我们将在编辑框中输入一些测试内容,并在我们刚刚添加的按钮的单击处理程序中编写一些代码。
按钮单击处理函数。 在 strData
中获取用户输入...
LRESULT CCMainDlg::OnBnClickedBtnSendDataToSilverlight
(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
CAtlStringW strData;
GetDlgItem(IDC_EDIT_DATA).GetWindowTextW(strData);
现在我们来谈谈关键点 - 获取我们在 Silverlight 应用程序中刚刚注册的 Communicator 对象的 DISPID
。
IDispatch *pContent;
HRESULT hr = CXcpControlHost::GetXcpControlPtr()->get_Content(&pContent);
CComBSTR bstrMember(L"Communicator");
DISPID dispIDCommunicator = NULL;
hr = pContent->GetIDsOfNames(IID_NULL, &bstrMember, 1,
LOCALE_SYSTEM_DEFAULT, &dispIDCommunicator);
if(FAILED(hr))
{
::MessageBox(NULL, L"Failed to get the DISPID for Communicator",
L"Error :(", 0);
return 0;
}
一旦我们获得了 Communicator
对象的有效 dispID
,我们就可以准备获取 Communicator 对象的 IDispatch*
。 这有点棘手,我们将使用 DISPATCH_PROPERTYGET
进行调用。
VARIANT pVarResult;
DISPPARAMS dispparams;
memset(&dispparams, 0, sizeof dispparams);
dispparams.cArgs = 0;
dispparams.rgvarg = NULL;
dispparams.cNamedArgs = 0;
// Getting IDispatch from for Scriptable object exposed by Silverlight Application.
// Passing dispid for "Communicator" to get its IDispatch* using DISPATCH_PROPERTYGET.
hr = pContent->Invoke(dispIDCommunicator,
IID_NULL,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET,
&dispparams, &pVarResult, NULL, NULL);
if(FAILED(hr))
{
::MessageBox(NULL, L"Failed to get the IDsipatch* of Communicator",
L"Error :(", 0);
return 0;
}
IDispatch* pCommunicatorDispatch = pVarResult.pdispVal;
我们将 Communicator 的 IDispatch*
存储在 pCommunicatorDispatch
中。 现在我们必须使用这个 pCommunicatorDispatch
。 这是我们现在的主要角色,使用 pCommunicatorDispatch
,我们将从 Silverlight 应用程序获取我们暴露的方法(SetDataInEditBox
)的 DISPID
,然后进行 Invoke()
调用,通过将该 string
传递到该函数来调用 SetDataInEditBox()
。
bstrMember = L"SetDataInTextBox";
DISPID dispIDSetDataInTextBox = NULL;
hr = pCommunicatorDispatch->GetIDsOfNames(IID_NULL,&bstrMember,1,
LOCALE_SYSTEM_DEFAULT,&dispIDSetDataInTextBox);
EXCEPINFO pexcepinfo ;
if(SUCCEEDED(hr))
{
dispparams.cArgs = 1;
dispparams.cNamedArgs = 1;
dispparams.rgvarg = new VARIANT[1];
dispparams.rgvarg[0].vt = VT_BSTR;
dispparams.rgvarg[0].bstrVal = SysAllocString(strData.GetString());
hr = pCommunicatorDispatch->Invoke(dispIDSetDataInTextBox,
IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD,
&dispparams, &pVarResult,&pexcepinfo,NULL);
delete [] dispparams.rgvarg;
if (hr != S_OK)
{
::MessageBox(NULL, L"Failed to Invoke Silverlight function",
L"Error :(", 0);
return 0;
}
}
else
{
::MessageBox(NULL, L"Failed to get the DISPID for SetDataInTextBox
function defined in Silverlight.", L"Error :(", 0);
}
结论
在本文中,我向您展示了如何从 C++ Silverlight 主机调用在 Silverlight 应用程序中定义的一个函数。
希望本文能对您在 Silverlight 和 C++ 交互方面有所帮助。
如有任何问题、意见和建议,请使用本文底部的评论区。
历史
- 2010 年 5 月 20 日:初始发布