c++ - 如何使用 native C++ 在 WinRT 中创建模式消息框

标签 c++ windows-runtime messagebox assertions

我目前正在开发一个跨平台的 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 调用时)。如果我继续执行,我将失去在正确位置触发断点的可能性。

所以我正在寻找的是某种强制重绘或“忙等待”异步调用完成的方法(例如“await messadeDialog->ShowAsync()”)。我知道我可以使用托管 C++,但我想避免使用它 :)

最佳答案

当您调用 ShowAsync() 来显示弹出窗口时,任务会安排在 UI 线程上执行。为了运行此任务,UI 线程必须可以自由执行它(即,它不能执行其他代码)。如果您的代码在 UI 线程上执行并且您调用了 ShowAsync(),那么您将阻塞直到 ShowAsync() 完成,您的应用程序将死锁:显示弹出窗口的任务必须等到您的代码停止在 UI 线程上运行,但您的代码在任务完成之前不会停止运行。

如果您想在 UI 线程上等待事件发生或异步操作完成,您需要调用一个同步函数来抽取队列,这样您就不会阻塞 UI 线程。例如,看看 the code in the Hilo project that allows synchronization of an asynchronous operation.

不幸的是,这仍然对您没有帮助,因为 Windows 应用商店应用程序 UI 在 Application Single-Threaded Apartment (ASTA) 中运行,这限制了重入。这是一件好事,因为意外的 COM 重入是许多最可怕的错误的原因。我不认为有一种方法可以在您的函数等待时运行“显示弹出窗口”任务。

但是,如果这只是为了调试,您可以调用MessageBox 来显示一个普通的消息框。它会出现在桌面上,但您的程序肯定会等待调用完成,然后再继续执行。您的应用不会通过调用 MessageBox 的商店认证,但同样,对于调试代码,它应该可以正常工作。

MessageBox 的声明在构建 Windows 应用商店应用程序时默认为 #ifdef,但您可以自己声明该函数。我写了一篇文章,"'printf' debugging in Metro style apps"这解释了如何做到这一点。


最后,快速说明一下:Windows 运行时没有“托管 C++”。 C++/CX 语言扩展在语法上类似于针对 .NET Framework 和 CLI 的 C++/CLI,但它们在语义上不同。使用 C++/CX 时,根本没有托管代码,运行时也不会加载 CLR。编译器将 C++/CX 代码转换为等效的 C++ 代码,然后编译该代码。全部 100% 原生。

关于c++ - 如何使用 native C++ 在 WinRT 中创建模式消息框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13312806/

相关文章:

c++ - cudaMallocPitch 和 cudaMemcpy2D

cryptography - WinRT 流加密

windows-8 - Windows RT/Windows Store App对App.config的回答是什么?

c# - 如何允许在 ListView/GridView 项控件内进行操作,同时允许在 ListView/GridView 上进行滚动和横向滑动操作?

c# - 显示消息后关闭应用程序

c# - 使用计时器在 Messagebox 中启用按钮

c++ - -std=c++ 98 和 OS X 10.10

c++ - golang select 语句是如何实现的?

c++ - 从 QDataStream 轻松读出到 QStringList

C#/WPF,如何使窗口(使用 Window.ShowDialog() 创建)在单击其父窗口时标题栏闪烁(就像 MessageBox 一样)?