如何使用本机C 在WinRT中创建模态消息框
How to create a modal messagebox in WinRT using native C++
目前我正在处理跨平台C SDK,我必须将我们的主张处理程序移植到Winrt。该过程的一部分是显示一个消息框,等待用户输入并在用户选择"调试"时触发断点。
我已经有一个消息框出现了,但是我找不到等待消息框出现的方法而没有离开当前执行点。
这是我到目前为止的代码。
// Create the message dialog factory
Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IMessageDialogFactory> messageDialogFactory;
Microsoft::WRL::Wrappers::HStringReference messageDialogFactoryId(RuntimeClass_Windows_UI_Popups_MessageDialog);
Windows::Foundation::GetActivationFactory(messageDialogFactoryId.Get(), messageDialogFactory.GetAddressOf() );
// Setup the used strings
Microsoft::WRL::Wrappers::HString message;
Microsoft::WRL::Wrappers::HString title;
Microsoft::WRL::Wrappers::HString labelDebug;
Microsoft::WRL::Wrappers::HString labelIgnore;
Microsoft::WRL::Wrappers::HString labelExit;
message.Set( L"Test" );
title.Set( L"Assertion triggered" );
labelDebug.Set(L"Debug");
labelIgnore.Set(L"Ignore");
labelExit.Set(L"Exit");
// Create the dialog object
Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IMessageDialog> messageDialog;
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::UI::Popups::IUICommand*>> messageDialogCommands;
messageDialogFactory->CreateWithTitle( message.Get(), title.Get(), messageDialog.GetAddressOf() );
messageDialog->get_Commands(messageDialogCommands.GetAddressOf());
// Attach commands
Microsoft::WRL::ComPtr<ABI::Windows::UI::Popups::IUICommandFactory> commandFactory;
Microsoft::WRL::Wrappers::HStringReference commandFactoryId(RuntimeClass_Windows_UI_Popups_UICommand);
Windows::Foundation::GetActivationFactory(commandFactoryId.Get(), commandFactory.GetAddressOf() );
CInvokeHandler commandListener;
commandFactory->CreateWithHandler(labelDebug.Get(), &commandListener, commandListener.m_DebugCmd.GetAddressOf() );
commandFactory->CreateWithHandler(labelIgnore.Get(), &commandListener, commandListener.m_IgnoreCmd.GetAddressOf() );
commandFactory->CreateWithHandler(labelExit.Get(), &commandListener, commandListener.m_ExitCmd.GetAddressOf() );
messageDialogCommands->Append( commandListener.m_DebugCmd.Get() );
messageDialogCommands->Append( commandListener.m_IgnoreCmd.Get() );
messageDialogCommands->Append( commandListener.m_ExitCmd.Get() );
// Show dialog
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::UI::Popups::IUICommand*>> showOperation;
messageDialog->ShowAsync( showOperation.GetAddressOf() );
// ... and wait for the user to choose ...?
现在我被困在这里。如果我只是为了触发回调而自旋等待,我将进入一个无尽的循环,而消息框根本没有显示(至少在我从UI-Thread打电话时)。如果我继续执行,我将失去在正确位置触发断点的可能性。
因此,我要寻找的是某种方法来强制重新绘制或"繁忙的等待",以供异步电话完成(sth。像"等待Messadedialog-> ShowAsync()")。我知道我可以使用托管C ,但是我想避免它:)
呼叫ShowAsync()
以显示弹出窗口时,该任务已安排在UI线程上执行。为了使此任务运行,UI线程必须自由执行(即,它不能执行其他代码)。如果您的代码在UI线程上执行并致电ShowAsync()
,则您将其阻止直到ShowAsync()
完成,您的应用程序将死锁:显示弹出窗口的任务必须等到您的代码停止在UI线程上运行,但是您的代码不会停止运行直到任务完成。
如果要在UI线程上等待事件发生或进行异步操作完成,则需要调用泵送队列的同步功能之一,以使您不会阻止UI线程。例如,查看允许同步操作同步的HILO项目中的代码。
不幸的是,这仍然没有帮助,因为Windows Store App UI在应用程序单线公寓(ASTA)中运行,这限制了重新输入。这是一件好事,因为意外的com重新段是许多最可怕的虫子的原因。我认为当您的功能等待时,没有办法运行"显示弹出式"任务。
但是,如果仅用于调试,则只需调用MessageBox
即可显示一个普通的消息框。它会显示在桌面上,但是您的程序肯定会等待呼叫完成,然后继续执行。您的应用程序不会通过拨打MessageBox
的商店认证,但对于调试代码,它应该可以正常工作。
在构建Windows Store应用程序时,默认情况下,MessageBox
的声明是#ifdef
'的,但是您可以自己声明该功能。我写了一篇文章,"'printf'在地铁风格应用中调试",其中解释了如何做到这一点。
最后,快速澄清:Windows运行时没有"托管C "。C /CX语言扩展是句法类似于C /CLI,它针对.NET框架和CLI,但它们在语义上是不同的。使用C /CX时,根本没有托管代码,并且在运行时不会加载CLR。编译器将C /CX代码转换为等效的C 代码,然后编译该代码。全部都是100%的本地人。
只是对我最终所做的快速跟进(感谢詹姆斯的回答)。
如果从UI线程触发断言(并且应用程序以STA运行),我只是断开并将消息放入调试中。从Metro应用程序触发桌面窗口对我来说似乎是错误的。如果从非UI线程触发断言,则"模态"框非常有效。
#include <ppltasks.h>
using namespace concurrency;
// ...
auto UIDispatcher = Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher;
try
{
auto uiTask = UIDispatcher->RunAsync( CoreDispatcherPriority::Normal,
ref new DispatchedHandler( [&messagePopup, cmds, &result]()
{
try
{
create_task(messagePopup->ShowAsync()).then([cmds, &result](IUICommand^ selected) {
// result is changed depending on which command was selected
});
}
catch (...)
{
}
}));
// Wait for the user to click
create_task(uiTask).wait();
// Sleep until result has been changed
}
catch ( invalid_operation )
{
// STA, debugout & break
}
// test on result, etc.
我不知道这实际上是最好的方法,但它有效:)
您需要将ShowAsync派遣到UI线程,否则在从非UI线程调用时会引发com异常。
我使用了第一个create_task()。然后(),因为我是懒惰的^^并检查用户交互。
create_task(uitask).wait()从STA调用时将投掷无效的操作(我猜MTA可以正常工作)。
在这种情况下,派遣的ShowAsync也会通过抛出com例外而失败,因此没有显示任何内容。最后,我只是忙着等待盒子的触发。
- 如何在QT中制作模态QProgressDialog?
- 如何让 QInputDialog 更少模态?
- cdhtmldialog-使其模态
- Qt - 创建主窗口前的非模态对话框
- 如何正确使用异常处理IWTH模态对话框
- 如何使用Ifileopendialog打开 *模态 *文件对话框
- 模态qprogressdialog :: setValue()导致嵌套事件循环崩溃
- 捕获新创建的模态对话框的窗口句柄
- 模态形式之上的主形式
- QT在菜单项上显示模态对话框(.UI)单击
- 如何将QMainWindow设置为模态
- 如何在堆栈上创建多态对象
- C++ 如何创建多态容器
- 在堆上创建多态对象的数据成员向量
- Qt中的多模态窗口
- 正在从Script/osx 10.7+/safari/automatior/objective-c中删除模态
- 自动对焦QLineEdit在QDialog与弹出标志和模态在主窗口
- VC6中的多模态对话框
- 创建一个向主窗体返回值的模态窗口
- 创建不显示的非模态对话框