@@ -3067,9 +3067,6 @@ TEST_CASE("COMEnumerator", "[com][enumerator]")
3067
3067
#include < winrt/windows.foundation.h>
3068
3068
#include < windows.foundation.h>
3069
3069
3070
- HANDLE g_hangHandle{nullptr };
3071
- HANDLE g_doneHangingHandle{nullptr };
3072
-
3073
3070
TEST_CASE (" com_timeout" , " [com][com_timeout]" )
3074
3071
{
3075
3072
auto init = wil::CoInitializeEx_failfast ();
@@ -3083,24 +3080,32 @@ TEST_CASE("com_timeout", "[com][com_timeout]")
3083
3080
// apartments (MTA -> STA in this case)
3084
3081
struct COMTimeoutTestObject : winrt::implements<COMTimeoutTestObject, winrt::Windows::Foundation::IStringable, winrt::non_agile>
3085
3082
{
3083
+ wil::shared_event _hangHandle;
3084
+ wil::shared_event _doneHangingHandle;
3085
+ std::shared_ptr<bool > _shouldHang;
3086
+ COMTimeoutTestObject (wil::shared_event hangHandle, wil::shared_event doneHangingHandle, std::shared_ptr<bool > shouldHang) :
3087
+ _hangHandle (hangHandle), _doneHangingHandle(doneHangingHandle), _shouldHang(shouldHang)
3088
+ {
3089
+ }
3090
+
3086
3091
winrt::hstring ToString ()
3087
3092
{
3088
- // If the global handle exists, block on it. If it doesn't exist then this is a non-hang case
3089
- // so skip waiting.
3090
- if (g_hangHandle)
3093
+ // If the test wants to block, then use the hang handles.
3094
+ if (*(_shouldHang.get ()))
3091
3095
{
3092
3096
// Pump messages so this STA thread is healthy while we wait. If this wait fails that means
3093
3097
// the cancel did not work.
3094
- HANDLE handles[1 ] = {g_hangHandle };
3098
+ HANDLE handles[1 ] = {_hangHandle. get () };
3095
3099
DWORD index ;
3096
3100
REQUIRE_SUCCEEDED (CoWaitForMultipleObjects (
3097
3101
CWMO_DISPATCH_CALLS | CWMO_DISPATCH_WINDOW_MESSAGES, 10000 , ARRAYSIZE (handles), handles, &index ));
3098
3102
3099
- if (g_doneHangingHandle )
3103
+ if (_doneHangingHandle )
3100
3104
{
3101
- SetEvent (g_doneHangingHandle );
3105
+ _doneHangingHandle. SetEvent ();
3102
3106
}
3103
3107
}
3108
+
3104
3109
return L" COMTimeoutTestObject" ;
3105
3110
}
3106
3111
};
@@ -3109,27 +3114,47 @@ TEST_CASE("com_timeout", "[com][com_timeout]")
3109
3114
// exit.
3110
3115
wil::shared_event comServerEvent;
3111
3116
comServerEvent.create ();
3117
+
3112
3118
wil::shared_event agileReferencePopulated;
3113
3119
agileReferencePopulated.create ();
3120
+
3121
+ // These handles are used to coordinate with the COM server thread. The first one causes it to block. The
3122
+ // done hanging event lets us know that it is done blocking and we can proceed with a second call that should
3123
+ // avoid reentering.
3124
+ wil::shared_event hangingHandle;
3125
+ hangingHandle.create ();
3126
+ wil::shared_event doneHangingHandle;
3127
+ doneHangingHandle.create ();
3128
+
3129
+ auto shouldHang = std::make_shared<bool >(false );
3130
+
3114
3131
wil::com_agile_ref agileStringable;
3115
3132
3116
- auto comServerThread = std::thread ([comServerEvent, agileReferencePopulated, &agileStringable] {
3117
- // This thread must be STA to pull RPC in as mediator between threads.
3118
- auto init = wil::CoInitializeEx_failfast (COINIT_APARTMENTTHREADED);
3133
+ auto comServerThread =
3134
+ std::thread ([comServerEvent, agileReferencePopulated, hangingHandle, doneHangingHandle, &agileStringable, shouldHang] {
3135
+ // This thread must be STA to pull RPC in as mediator between threads.
3136
+ auto init = wil::CoInitializeEx_failfast (COINIT_APARTMENTTHREADED);
3119
3137
3120
- const auto stringable = winrt::make<COMTimeoutTestObject>();
3121
- agileStringable = wil::com_agile_query (stringable.as <ABI::Windows::Foundation::IStringable>().get ());
3138
+ const auto stringable = winrt::make<COMTimeoutTestObject>(hangingHandle, doneHangingHandle, shouldHang );
3139
+ agileStringable = wil::com_agile_query (stringable.as <ABI::Windows::Foundation::IStringable>().get ());
3122
3140
3123
- agileReferencePopulated.SetEvent ();
3141
+ agileReferencePopulated.SetEvent ();
3124
3142
3125
- // Pump messages so this STA thread is healthy.
3126
- HANDLE handles[1 ] = {comServerEvent.get ()};
3127
- DWORD index ;
3128
- REQUIRE_SUCCEEDED (CoWaitForMultipleObjects (
3129
- CWMO_DISPATCH_CALLS | CWMO_DISPATCH_WINDOW_MESSAGES, 10000 , ARRAYSIZE (handles), handles, &index ));
3143
+ // Pump messages so this STA thread is healthy.
3144
+ HANDLE handles[1 ] = {comServerEvent.get ()};
3145
+ DWORD index ;
3146
+ REQUIRE_SUCCEEDED (CoWaitForMultipleObjects (
3147
+ CWMO_DISPATCH_CALLS | CWMO_DISPATCH_WINDOW_MESSAGES, INFINITE, ARRAYSIZE (handles), handles, &index ));
3148
+ });
3149
+
3150
+ auto makeSureComServerThreadExits = wil::scope_exit ([comServerEvent, &comServerThread] {
3151
+ // We are done testing. Tell the STA thread to exit and then block until it is done.
3152
+ comServerEvent.SetEvent ();
3153
+
3154
+ comServerThread.join ();
3130
3155
});
3131
3156
3132
- agileReferencePopulated.wait (5000 );
3157
+ REQUIRE_SUCCEEDED ( agileReferencePopulated.wait (5000 ) );
3133
3158
3134
3159
SECTION (" Basic construction nothrow" )
3135
3160
{
@@ -3151,42 +3176,33 @@ TEST_CASE("com_timeout", "[com][com_timeout]")
3151
3176
}
3152
3177
SECTION (" RPC timeout test" )
3153
3178
{
3154
- // These handles are used to coordinate with the COM server thread. The first one causes it to block. The
3155
- // done hanging event lets us know that it is done blocking and we can proceed with a second call that should
3156
- // avoid reentering.
3157
- wil::unique_event hangHandle;
3158
- hangHandle.create ();
3159
- g_hangHandle = hangHandle.get ();
3160
-
3161
- wil::unique_event doneHangingHandle;
3162
- doneHangingHandle.create ();
3163
- g_doneHangingHandle = doneHangingHandle.get ();
3164
-
3165
3179
wil::com_timeout timeout{100 };
3166
3180
3181
+ *(shouldHang.get ()) = true ;
3182
+
3167
3183
// The timeout is now in place. The blocking call should cancel in a timely manner and fail with RPC_E_CALL_CANCELED.
3168
3184
wil::com_ptr<ABI::Windows::Foundation::IStringable> localServer =
3169
3185
agileStringable.query <ABI::Windows::Foundation::IStringable>();
3170
3186
wil::unique_hstring value;
3171
- REQUIRE (localServer->ToString (&value) == RPC_E_CALL_CANCELED);
3187
+ auto localServerResult = localServer->ToString (&value);
3188
+ REQUIRE (static_cast <bool >(localServerResult == RPC_E_CALL_CANCELED));
3172
3189
REQUIRE (timeout.timed_out ());
3173
3190
3174
- hangHandle .SetEvent ();
3191
+ hangingHandle .SetEvent ();
3175
3192
REQUIRE (doneHangingHandle.wait (5000 ));
3176
3193
3177
- hangHandle .ResetEvent ();
3194
+ hangingHandle .ResetEvent ();
3178
3195
3179
3196
// Make a second blocking call within the lifetime of the same com_timeout instance. This second call should also
3180
3197
// cancel and return.
3181
- const auto result = localServer->ToString (&value);
3182
- REQUIRE (result == RPC_E_CALL_CANCELED);
3198
+ localServerResult = localServer->ToString (&value);
3199
+ REQUIRE (static_cast < bool >(localServerResult == RPC_E_CALL_CANCELED) );
3183
3200
REQUIRE (timeout.timed_out ());
3184
3201
3185
- hangHandle .SetEvent ();
3202
+ hangingHandle .SetEvent ();
3186
3203
REQUIRE (doneHangingHandle.wait (5000 ));
3187
3204
3188
- g_hangHandle = nullptr ;
3189
- g_doneHangingHandle = nullptr ;
3205
+ *(shouldHang.get ()) = false ;
3190
3206
}
3191
3207
SECTION (" Non-timeout unaffected test" )
3192
3208
{
@@ -3200,13 +3216,6 @@ TEST_CASE("com_timeout", "[com][com_timeout]")
3200
3216
REQUIRE (!timeout.timed_out ());
3201
3217
REQUIRE (std::wstring_view{L" COMTimeoutTestObject" } == WindowsGetStringRawBuffer (value.get (), nullptr ));
3202
3218
}
3203
-
3204
- // We are done testing. Tell the STA thread to exit and then block until it is done.
3205
- comServerEvent.SetEvent ();
3206
- comServerThread.join ();
3207
-
3208
- g_hangHandle = nullptr ;
3209
- g_doneHangingHandle = nullptr ;
3210
3219
}
3211
3220
#endif // defined(__cpp_impl_coroutine) || defined(__cpp_coroutines) || defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
3212
3221
#endif // (NTDDI_VERSION >= NTDDI_WINBLUE)
0 commit comments