如何使用本机C ++在WinRT中创建模式消息框 [英] How to create a modal messagebox in WinRT using native C++

查看:159
本文介绍了如何使用本机C ++在WinRT中创建模式消息框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我正在开发一个跨平台的C ++ SDK,并且必须将断言处理程序移植到WinRT.该过程的一部分是显示一个消息框,等待用户输入并在用户选择调试"时触发断点.

I'm working on a cross-platform C++ SDK at the moment and I have to port our assert handler to WinRT. One part of the process is to display a message box, wait for the user input and trigger a breakpoint when the user selects "debug".

我已经出现了一个消息框,但是我找不到一种方法来等待消息框显示而没有离开当前执行点.

I already got a message box to appear, but I cannot find a way to wait for the message box to appear without leaving the current point of execution.

到目前为止,这是我的代码.

Here is my code so far.

// 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调用时).如果我继续执行,我将失去在正确位置触发断点的可能性.

And now I'm stuck here. If I just spin-wait for the callback to be triggered I'm entering an endless loop and the message box does not show at all (at least when I'm calling from the UI-Thread). If I continue execution I'm losing the possibility to trigger a breakpoint at the correct position.

所以我要寻找的是某种方式来强制重画或忙-等待"以完成异步调用(例如"await messadeDialog-> ShowAsync()").我知道我可以使用托管C ++,但是我想避免使用它:)

So what I'm looking for is some way to force a redraw or to "busy-wait" for the async call to finish (sth. like "await messadeDialog->ShowAsync()"). I know I could use managed-C++, but I would like to avoid it :)

推荐答案

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

When you call ShowAsync() to show the popup, the task is scheduled for execution on the UI thread. In order for this task to run, the UI thread must be free to execute it (i.e., it can't be executing other code). If your code is executing on the UI thread and you call ShowAsync(), then you block until ShowAsync() completes, your application will deadlock: the task to show the popup must wait until your code stops running on the UI thread, but your code will not stop running until the task completes.

如果要在UI线程上等待事件发生或异步操作完成,则需要调用抽水队列的同步函数之一,以免阻塞UI线程.例如,看看 Hilo项目中允许异步操作的同步.

If you want to wait on the UI thread for an event to happen or for an asynchronous operation to complete, you need to call one of the synchronization functions that pumps the queue so that you don't block the UI thread. For example, take a look at the code in the Hilo project that allows synchronization of an asynchronous operation.

不幸的是,这仍然无济于事,因为Windows Store应用程序UI在应用程序单线程单元(ASTA),它限制了可重入性.这是一件好事,因为意外的COM重新进入是导致许多最可怕的错误的原因.我不认为有一种方法可以在您的函数等待时运行显示弹出窗口"任务.

Unfortunately, this still doesn't help you, because Windows Store app UI runs in an Application Single-Threaded Apartment (ASTA), which restricts reentrancy. This is a good thing, because unexpected COM reentrancy is the cause of many of the most horrible of horrible bugs. I don't think there is a way to run the "show the popup" task while your function waits.

但是,如果仅用于调试,则可以调用 MessageBox 来显示普通的消息框.它会显示在桌面上,但是您的程序肯定会在继续执行之前等待调用完成.您的应用不会通过调用 MessageBox 的方式通过商店认证,但是同样,对于调试代码,它应该可以正常工作.

However, if this is only for debugging, you can just call MessageBox to show an ordinary message box. It'll show up on the desktop, but your program will definitely wait for the call to complete before continuing execution. Your app won't pass store certification with a call to MessageBox in place, but again, for debug code, it should work fine.

在构建Windows应用商店应用时,默认情况下, #ifdef 声明了 MessageBox 的声明,但是您可以自己声明该函数.我写了一篇文章,在Metro中调试'printf'样式的应用程序" ,其中介绍了操作方法.

The declaration of MessageBox is #ifdef'ed out by default when building a Windows Store app, but you can declare the function yourself. I wrote an article, "'printf' debugging in Metro style apps" that explains how to do this.

最后,快速澄清一下:Windows运行时没有托管C ++".C ++/CX语言扩展在语法上 与C ++/CLI类似,后者以.NET Framework和CLI为目标,但在语义上不同.使用C ++/CX时,根本没有托管代码,并且在运行时不会加载CLR.编译器将C ++/CX代码转换为等效的C ++代码,然后编译该代码.都是100%原生的.

Finally, a quick clarification: there is no "managed C++" for the Windows Runtime. The C++/CX language extensions are syntactically similar to C++/CLI, which targets the .NET Framework and the CLI, but they are semantically different. When using C++/CX, there's no managed code at all and the CLR will not be loaded at runtime. The compiler transforms C++/CX code into equivalent C++ code, then compiles that code. It's all 100% native.

这篇关于如何使用本机C ++在WinRT中创建模式消息框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆