none
从自己写的WinRT DLL中的异步方法中返回一个包含String的Task, 上层应用的Message Dialog为何会报“找不到元素”? RRS feed

  • 问题

  • WinRT DLL 的代码片段如下:

    //功能: 发送和接收
    //输入参数: Hex格式的指令字符串
    //返回结果: 成功则返回包含Hex格式字符串的task
    task<String^>  CBTWinRTDLL::SendAndRecvDataAsync(String^ sendData)
    {
    	//将字符串从String^ 转成 std:string
    	std::string str = pstos(sendData);
    
    	//Trim all white spaces 去掉所有空格
    	std::string searchString(" ");
    	std::string replaceString("");
    	std::string::size_type pos = 0;
    	while ((pos = str.find(searchString, pos)) != std::string::npos)
    	{
    		str.replace(pos, searchString.size(), replaceString);
    		pos++;
    	}
    
    	//如果输入字符串长度0, 函数返回
    	int len = str.length();
    	if (0 == len)
    	{
    		//返回,输入数据长度错误
    		return task<String^>([]()
    		{
    			String^ retStr = "string length == 0";
    			return retStr;
    		});
    	}
            else
            {
             ......
            }
    }


    上层 Store APP代码片段:

    //发送和接收按钮
    void BTApp_CPP::MainPage::Btn_SendData_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	task<String^> SendTask = task<String^>(btDLL.SendAndRecvDataAsync(this->TxtBox_DataSend->Text));
    
    	SendTask.then([this](task<String^> sendTask)
    	{
    		try
    		{
    			String^ retStr = sendTask.get();
    			MessageDialog^ md = ref new MessageDialog("Devices connected to: " + "\r\n" + retStr, "Windows store app");
    			md->ShowAsync();
    		}
    		catch (Exception^ ex)
    		{
    			MessageDialog^ md = ref new MessageDialog("Exception message: " + ex->Message, "Windows store app");
    			md->ShowAsync();
    		}
    	});
    
    }

    错误出现在try块中:

    try
    {
    String^ retStr = sendTask.get();
    MessageDialog^ md = ref new MessageDialog("Devices connected to: " + "\r\n" + retStr, "Windows store app");
    md->ShowAsync();
    }

    这一行报错:md->ShowAsync();

    错误信息是:

    First-chance exception at 0x76A72EEC in BTApp_CPP.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x0B5EE7FC. HRESULT:0x80070490 找不到元素。

    WinRT 信息: 找不到元素。

    堆栈跟踪:
    [外部代码]
    BTApp_CPP.exe!BTApp_CPP::MainPage::Btn_SendData_Click::__l5::<lambda>(Concurrency::task<Platform::String ^> sendTask) 行 163
    [外部代码]

    如有适用于此异常的处理程序,该程序便可安全地继续运行。

    下面是错误截屏:


    nio


    • 已编辑 nio Pan 2013年12月24日 9:08
    2013年12月24日 9:07

答案

  • 你好 nio Pan,

    你的try 代码块儿是执行在 worker thread(工作线程),在工作线程中你无法使用 MessageDialog(UI线程限定)。

    不过如果你想在工作线程更新UI 线程, 你可以使用 CoreDispatcher 的 RunAsync 方法。示例如下:

    _dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this]() {

    MessageDialog^ md = ref new MessageDialog("Devices connected to: " + "\r\n" + retStr, "Windows store app");
    md
    ->ShowAsync();
    }));

    如果你想更深入的了解该方法,请参考以下内容:

    http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.core.coredispatcher.runasync.aspx

    因无中文版本,所以上文是英文版本,如还有疑问,请告知我们。

    圣诞快乐!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 nio Pan 2013年12月25日 6:54
    2013年12月25日 2:33
    版主
  • Thanks Xiaoliang,

    我解决了这个问题,实际上是我从WinRT DLL的函数中返回时,返回的值是包括在一个background线程中的,所以调用方在UI线程上拿不到值。因此我在WinRT DLL工程的代码里修改一下返回的Task:

    将:

    if (0 == len)
    	{
    		//返回,输入数据长度错误
    		return task<String^>([]()
    		{
    			String^ retStr = "string length == 0";
    			return retStr;
    		});
    	}

    改为

    	//如果输入参数的长度为0, 函数返回
    	if (0 == len)
    	{
    		auto op = create_async([]()
    		{
    		});
    
    		return create_task(op).then([]()
    		{
    			String^ retStr = "Data for send cannot be empty.";
    			return retStr;
    		});
    	}
    



    nio

    • 已标记为答案 nio Pan 2013年12月25日 6:54
    2013年12月25日 6:53

全部回复

  • 你好 nio Pan,

    你的try 代码块儿是执行在 worker thread(工作线程),在工作线程中你无法使用 MessageDialog(UI线程限定)。

    不过如果你想在工作线程更新UI 线程, 你可以使用 CoreDispatcher 的 RunAsync 方法。示例如下:

    _dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal, ref new Windows::UI::Core::DispatchedHandler([this]() {

    MessageDialog^ md = ref new MessageDialog("Devices connected to: " + "\r\n" + retStr, "Windows store app");
    md
    ->ShowAsync();
    }));

    如果你想更深入的了解该方法,请参考以下内容:

    http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.core.coredispatcher.runasync.aspx

    因无中文版本,所以上文是英文版本,如还有疑问,请告知我们。

    圣诞快乐!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • 已标记为答案 nio Pan 2013年12月25日 6:54
    2013年12月25日 2:33
    版主
  • Thanks Xiaoliang,

    我解决了这个问题,实际上是我从WinRT DLL的函数中返回时,返回的值是包括在一个background线程中的,所以调用方在UI线程上拿不到值。因此我在WinRT DLL工程的代码里修改一下返回的Task:

    将:

    if (0 == len)
    	{
    		//返回,输入数据长度错误
    		return task<String^>([]()
    		{
    			String^ retStr = "string length == 0";
    			return retStr;
    		});
    	}

    改为

    	//如果输入参数的长度为0, 函数返回
    	if (0 == len)
    	{
    		auto op = create_async([]()
    		{
    		});
    
    		return create_task(op).then([]()
    		{
    			String^ retStr = "Data for send cannot be empty.";
    			return retStr;
    		});
    	}
    



    nio

    • 已标记为答案 nio Pan 2013年12月25日 6:54
    2013年12月25日 6:53