1 //********************************************************* 2 // 3 // Copyright (c) Microsoft. All rights reserved. 4 // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 // 9 //********************************************************* 10 11 // 12 // AdvancedCapture.xaml.cpp 13 // Implementation of the AdvancedCapture class 14 // 15 16 #include "pch.h" 17 #include "AdvancedCapture.xaml.h" 18 19 using namespace SDKSample::MediaCapture; 20 21 using namespace Windows::UI::Xaml; 22 using namespace Windows::UI::Xaml::Navigation; 23 using namespace Windows::UI::Xaml::Data; 24 using namespace Windows::System; 25 using namespace Windows::Foundation; 26 using namespace Windows::Foundation::Collections; 27 using namespace Platform; 28 using namespace Windows::UI; 29 using namespace Windows::UI::Core; 30 using namespace Windows::UI::Xaml; 31 using namespace Windows::UI::Xaml::Controls; 32 using namespace Windows::UI::Xaml::Data; 33 using namespace Windows::UI::Xaml::Media; 34 using namespace Windows::Storage; 35 using namespace Windows::Media::MediaProperties; 36 using namespace Windows::Storage::Streams; 37 using namespace Windows::System; 38 using namespace Windows::UI::Xaml::Media::Imaging; 39 using namespace Windows::Devices::Enumeration; 40 41 ref class ReencodeState sealed 42 { 43 public: 44 ReencodeState() 45 { 46 } 47 48 virtual ~ReencodeState() 49 { 50 if (InputStream != nullptr) 51 { 52 delete InputStream; 53 } 54 if (OutputStream != nullptr) 55 { 56 delete OutputStream; 57 } 58 } 59 60 internal: 61 Windows::Storage::Streams::IRandomAccessStream ^InputStream; 62 Windows::Storage::Streams::IRandomAccessStream ^OutputStream; 63 Windows::Storage::StorageFile ^PhotoStorage; 64 Windows::Graphics::Imaging::BitmapDecoder ^Decoder; 65 Windows::Graphics::Imaging::BitmapEncoder ^Encoder; 66 }; 67 68 AdvancedCapture::AdvancedCapture() 69 { 70 InitializeComponent(); 71 ScenarioInit(); 72 } 73 74 /// <summary> 75 /// Invoked when this page is about to be displayed in a Frame. 76 /// </summary> 77 /// <param name="e">Event data that describes how this page was reached. The Parameter 78 /// property is typically used to configure the page.</param> 79 void AdvancedCapture::OnNavigatedTo(NavigationEventArgs^ e) 80 { 81 // A pointer back to the main page. This is needed if you want to call methods in MainPage such 82 // as NotifyUser() 83 rootPage = MainPage::Current; 84 85 m_orientationChangedEventToken = Windows::Graphics::Display::DisplayProperties::OrientationChanged += ref new Windows::Graphics::Display::DisplayPropertiesEventHandler(this, &AdvancedCapture::DisplayProperties_OrientationChanged); 86 } 87 88 void AdvancedCapture::OnNavigatedFrom(NavigationEventArgs^ e) 89 { 90 Windows::Media::MediaControl::SoundLevelChanged -= m_eventRegistrationToken; 91 Windows::Graphics::Display::DisplayProperties::OrientationChanged -= m_orientationChangedEventToken; 92 } 93 94 void AdvancedCapture::ScenarioInit() 95 { 96 rootPage = MainPage::Current; 97 btnStartDevice2->IsEnabled = true; 98 btnStartPreview2->IsEnabled = false; 99 m_bRecording = false; 100 m_bPreviewing = false; 101 m_bEffectAdded = false; 102 previewElement2->Source = nullptr; 103 ShowStatusMessage(""); 104 EffectTypeCombo->IsEnabled = false; 105 previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; 106 EnumerateWebcamsAsync(); 107 m_bSuspended = false; 108 } 109 110 void AdvancedCapture::ScenarioReset() 111 { 112 previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Collapsed; 113 ScenarioInit(); 114 } 115 116 void AdvancedCapture::Failed(Windows::Media::Capture::MediaCapture ^currentCaptureObject, Windows::Media::Capture::MediaCaptureFailedEventArgs^ currentFailure) 117 { 118 String ^message = "Fatal error" + currentFailure->Message; 119 create_task(Dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::High, 120 ref new Windows::UI::Core::DispatchedHandler([this, message]() 121 { 122 ShowStatusMessage(message); 123 }))); 124 } 125 126 void AdvancedCapture::btnStartDevice_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 127 { 128 try 129 { 130 EnableButton(false, "StartDevice"); 131 ShowStatusMessage("Starting device"); 132 auto mediaCapture = ref new Windows::Media::Capture::MediaCapture(); 133 m_mediaCaptureMgr = mediaCapture; 134 auto settings = ref new Windows::Media::Capture::MediaCaptureInitializationSettings(); 135 auto chosenDevInfo = m_devInfoCollection->GetAt(EnumedDeviceList2->SelectedIndex); 136 settings->VideoDeviceId = chosenDevInfo->Id; 137 if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Back) 138 { 139 m_bRotateVideoOnOrientationChange = true; 140 m_bReversePreviewRotation = false; 141 } 142 else if (chosenDevInfo->EnclosureLocation != nullptr && chosenDevInfo->EnclosureLocation->Panel == Windows::Devices::Enumeration::Panel::Front) 143 { 144 m_bRotateVideoOnOrientationChange = true; 145 m_bReversePreviewRotation = true; 146 } 147 else 148 { 149 m_bRotateVideoOnOrientationChange = false; 150 } 151 152 create_task(mediaCapture->InitializeAsync(settings)).then([this](task<void> initTask) 153 { 154 try 155 { 156 initTask.get(); 157 158 auto mediaCapture = m_mediaCaptureMgr.Get(); 159 160 DisplayProperties_OrientationChanged(nullptr); 161 162 EnableButton(true, "StartPreview"); 163 EnableButton(true, "StartStopRecord"); 164 EnableButton(true, "TakePhoto"); 165 ShowStatusMessage("Device initialized successful"); 166 EffectTypeCombo->IsEnabled = true; 167 mediaCapture->Failed += ref new Windows::Media::Capture::MediaCaptureFailedEventHandler(this, &AdvancedCapture::Failed); 168 } 169 catch (Exception ^ e) 170 { 171 ShowExceptionMessage(e); 172 } 173 }); 174 } 175 catch (Platform::Exception^ e) 176 { 177 ShowExceptionMessage(e); 178 } 179 } 180 181 void AdvancedCapture::btnStartPreview_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 182 { 183 m_bPreviewing = false; 184 try 185 { 186 ShowStatusMessage("Starting preview"); 187 EnableButton(false, "StartPreview"); 188 189 auto mediaCapture = m_mediaCaptureMgr.Get(); 190 previewCanvas2->Visibility = Windows::UI::Xaml::Visibility::Visible; 191 previewElement2->Source = mediaCapture; 192 create_task(mediaCapture->StartPreviewAsync()).then([this](task<void> previewTask) 193 { 194 try 195 { 196 previewTask.get(); 197 m_bPreviewing = true; 198 ShowStatusMessage("Start preview successful"); 199 } 200 catch (Exception ^e) 201 { 202 ShowExceptionMessage(e); 203 } 204 }); 205 } 206 catch (Platform::Exception^ e) 207 { 208 m_bPreviewing = false; 209 previewElement2->Source = nullptr; 210 EnableButton(true, "StartPreview"); 211 ShowExceptionMessage(e); 212 } 213 } 214 215 void AdvancedCapture::lstEnumedDevices_SelectionChanged(Platform::Object^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs^ e) 216 { 217 if ( m_bPreviewing ) 218 { 219 create_task(m_mediaCaptureMgr->StopPreviewAsync()).then([this](task<void> previewTask) 220 { 221 try 222 { 223 previewTask.get(); 224 m_bPreviewing = false; 225 } 226 catch (Exception ^e) 227 { 228 ShowExceptionMessage(e); 229 } 230 }); 231 } 232 233 btnStartDevice2->IsEnabled = true; 234 btnStartPreview2->IsEnabled = false; 235 m_bRecording = false; 236 previewElement2->Source = nullptr; 237 EffectTypeCombo->IsEnabled = false; 238 m_bEffectAdded = false; 239 m_bEffectAddedToRecord = false; 240 m_bEffectAddedToPhoto = false; 241 ShowStatusMessage(""); 242 } 243 244 void AdvancedCapture::EnumerateWebcamsAsync() 245 { 246 try 247 { 248 ShowStatusMessage("Enumerating Webcams..."); 249 m_devInfoCollection = nullptr; 250 251 EnumedDeviceList2->Items->Clear(); 252 253 task<DeviceInformationCollection^>(DeviceInformation::FindAllAsync(DeviceClass::VideoCapture)).then([this](task<DeviceInformationCollection^> findTask) 254 { 255 try 256 { 257 m_devInfoCollection = findTask.get(); 258 if (m_devInfoCollection == nullptr || m_devInfoCollection->Size == 0) 259 { 260 ShowStatusMessage("No WebCams found."); 261 } 262 else 263 { 264 for(unsigned int i = 0; i < m_devInfoCollection->Size; i++) 265 { 266 auto devInfo = m_devInfoCollection->GetAt(i); 267 EnumedDeviceList2->Items->Append(devInfo->Name); 268 } 269 EnumedDeviceList2->SelectedIndex = 0; 270 ShowStatusMessage("Enumerating Webcams completed successfully."); 271 btnStartDevice2->IsEnabled = true; 272 } 273 } 274 catch (Exception ^e) 275 { 276 ShowExceptionMessage(e); 277 } 278 }); 279 } 280 catch (Platform::Exception^ e) 281 { 282 ShowExceptionMessage(e); 283 } 284 } 285 286 void AdvancedCapture::AddEffectToImageStream() 287 { 288 auto mediaCapture = m_mediaCaptureMgr.Get(); 289 Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; 290 291 if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && 292 (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewPhotoStreamsIdentical) && 293 (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::RecordPhotoStreamsIdentical)) 294 { 295 Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); 296 if(props->Type->Equals("Image")) 297 { 298 //Switch to a video media type instead since we cant add an effect to a image media type 299 Windows::Foundation::Collections::IVectorView<Windows::Media::MediaProperties::IMediaEncodingProperties^>^ supportedPropsList = mediaCapture->VideoDeviceController->GetAvailableMediaStreamProperties(Windows::Media::Capture::MediaStreamType::Photo); 300 { 301 unsigned int i = 0; 302 while (i < supportedPropsList->Size) 303 { 304 Windows::Media::MediaProperties::IMediaEncodingProperties^ props = supportedPropsList->GetAt(i); 305 306 String^ s = props->Type; 307 if(props->Type->Equals("Video")) 308 { 309 task<void>(mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(Windows::Media::Capture::MediaStreamType::Photo,props)).then([this](task<void> changeTypeTask) 310 { 311 try 312 { 313 changeTypeTask.get(); 314 ShowStatusMessage("Change type on photo stream successful"); 315 //Now add the effect on the image pin 316 task<void>(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"OcvTransform.OcvImageManipulations", nullptr)).then([this](task<void> effectTask3) 317 { 318 try 319 { 320 effectTask3.get(); 321 m_bEffectAddedToPhoto = true; 322 ShowStatusMessage("Adding effect to photo stream successful"); 323 EffectTypeCombo->IsEnabled = true; 324 325 } 326 catch(Exception ^e) 327 { 328 ShowExceptionMessage(e); 329 EffectTypeCombo->IsEnabled = true; 330 } 331 }); 332 333 } 334 catch(Exception ^e) 335 { 336 ShowExceptionMessage(e); 337 EffectTypeCombo->IsEnabled = true; 338 } 339 340 }); 341 break; 342 343 } 344 i++; 345 } 346 } 347 } 348 else 349 { 350 //Add the effect to the image pin if the type is already "Video" 351 task<void>(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::Photo,"OcvTransform.OcvImageManipulations", nullptr)).then([this](task<void> effectTask3) 352 { 353 try 354 { 355 effectTask3.get(); 356 m_bEffectAddedToPhoto = true; 357 ShowStatusMessage("Adding effect to photo stream successful"); 358 EffectTypeCombo->IsEnabled = true; 359 360 } 361 catch(Exception ^e) 362 { 363 ShowExceptionMessage(e); 364 EffectTypeCombo->IsEnabled = true; 365 } 366 }); 367 } 368 } 369 } 370 371 void AdvancedCapture::ShowStatusMessage(Platform::String^ text) 372 { 373 rootPage->NotifyUser(text, NotifyType::StatusMessage); 374 } 375 376 void AdvancedCapture::ShowExceptionMessage(Platform::Exception^ ex) 377 { 378 rootPage->NotifyUser(ex->Message, NotifyType::ErrorMessage); 379 } 380 381 void AdvancedCapture::EnableButton(bool enabled, String^ name) 382 { 383 if (name->Equals("StartDevice")) 384 { 385 btnStartDevice2->IsEnabled = enabled; 386 } 387 else if (name->Equals("StartPreview")) 388 { 389 btnStartPreview2->IsEnabled = enabled; 390 } 391 } 392 393 task<Windows::Storage::StorageFile^> AdvancedCapture::ReencodePhotoAsync( 394 Windows::Storage::StorageFile ^tempStorageFile, 395 Windows::Storage::FileProperties::PhotoOrientation photoRotation) 396 { 397 ReencodeState ^state = ref new ReencodeState(); 398 399 return create_task(tempStorageFile->OpenAsync(Windows::Storage::FileAccessMode::Read)).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) 400 { 401 state->InputStream = stream; 402 return Windows::Graphics::Imaging::BitmapDecoder::CreateAsync(state->InputStream); 403 }).then([state](Windows::Graphics::Imaging::BitmapDecoder ^decoder) 404 { 405 state->Decoder = decoder; 406 return Windows::Storage::KnownFolders::PicturesLibrary->CreateFileAsync(PHOTO_FILE_NAME, Windows::Storage::CreationCollisionOption::GenerateUniqueName); 407 }).then([state](Windows::Storage::StorageFile ^storageFile) 408 { 409 state->PhotoStorage = storageFile; 410 return state->PhotoStorage->OpenAsync(Windows::Storage::FileAccessMode::ReadWrite); 411 }).then([state](Windows::Storage::Streams::IRandomAccessStream ^stream) 412 { 413 state->OutputStream = stream; 414 state->OutputStream->Size = 0; 415 return Windows::Graphics::Imaging::BitmapEncoder::CreateForTranscodingAsync(state->OutputStream, state->Decoder); 416 }).then([state, photoRotation](Windows::Graphics::Imaging::BitmapEncoder ^encoder) 417 { 418 state->Encoder = encoder; 419 auto properties = ref new Windows::Graphics::Imaging::BitmapPropertySet(); 420 properties->Insert("System.Photo.Orientation", 421 ref new Windows::Graphics::Imaging::BitmapTypedValue((unsigned short)photoRotation, Windows::Foundation::PropertyType::UInt16)); 422 return create_task(state->Encoder->BitmapProperties->SetPropertiesAsync(properties)); 423 }).then([state]() 424 { 425 return state->Encoder->FlushAsync(); 426 }).then([tempStorageFile, state](task<void> previousTask) 427 { 428 auto result = state->PhotoStorage; 429 delete state; 430 431 tempStorageFile->DeleteAsync(Windows::Storage::StorageDeleteOption::PermanentDelete); 432 433 previousTask.get(); 434 435 return result; 436 }); 437 } 438 439 Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::GetCurrentPhotoRotation() 440 { 441 bool counterclockwiseRotation = m_bReversePreviewRotation; 442 443 if (m_bRotateVideoOnOrientationChange) 444 { 445 return PhotoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation); 446 } 447 else 448 { 449 return Windows::Storage::FileProperties::PhotoOrientation::Normal; 450 } 451 } 452 453 void AdvancedCapture::PrepareForVideoRecording() 454 { 455 Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); 456 if (mediaCapture == nullptr) 457 { 458 return; 459 } 460 461 bool counterclockwiseRotation = m_bReversePreviewRotation; 462 463 if (m_bRotateVideoOnOrientationChange) 464 { 465 mediaCapture->SetRecordRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); 466 } 467 else 468 { 469 mediaCapture->SetRecordRotation(Windows::Media::Capture::VideoRotation::None); 470 } 471 } 472 473 void AdvancedCapture::DisplayProperties_OrientationChanged(Platform::Object^ sender) 474 { 475 Windows::Media::Capture::MediaCapture ^mediaCapture = m_mediaCaptureMgr.Get(); 476 if (mediaCapture == nullptr) 477 { 478 return; 479 } 480 481 bool previewMirroring = mediaCapture->GetPreviewMirroring(); 482 bool counterclockwiseRotation = (previewMirroring && !m_bReversePreviewRotation) || 483 (!previewMirroring && m_bReversePreviewRotation); 484 485 if (m_bRotateVideoOnOrientationChange) 486 { 487 mediaCapture->SetPreviewRotation(VideoRotationLookup(Windows::Graphics::Display::DisplayProperties::CurrentOrientation, counterclockwiseRotation)); 488 } 489 else 490 { 491 mediaCapture->SetPreviewRotation(Windows::Media::Capture::VideoRotation::None); 492 } 493 } 494 495 Windows::Storage::FileProperties::PhotoOrientation AdvancedCapture::PhotoRotationLookup( 496 Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) 497 { 498 switch (displayOrientation) 499 { 500 case Windows::Graphics::Display::DisplayOrientations::Landscape: 501 return Windows::Storage::FileProperties::PhotoOrientation::Normal; 502 503 case Windows::Graphics::Display::DisplayOrientations::Portrait: 504 return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate270: 505 Windows::Storage::FileProperties::PhotoOrientation::Rotate90; 506 507 case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: 508 return Windows::Storage::FileProperties::PhotoOrientation::Rotate180; 509 510 case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: 511 return (counterclockwise) ? Windows::Storage::FileProperties::PhotoOrientation::Rotate90 : 512 Windows::Storage::FileProperties::PhotoOrientation::Rotate270; 513 514 default: 515 return Windows::Storage::FileProperties::PhotoOrientation::Unspecified; 516 } 517 } 518 519 Windows::Media::Capture::VideoRotation AdvancedCapture::VideoRotationLookup( 520 Windows::Graphics::Display::DisplayOrientations displayOrientation, bool counterclockwise) 521 { 522 switch (displayOrientation) 523 { 524 case Windows::Graphics::Display::DisplayOrientations::Landscape: 525 return Windows::Media::Capture::VideoRotation::None; 526 527 case Windows::Graphics::Display::DisplayOrientations::Portrait: 528 return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise270Degrees : 529 Windows::Media::Capture::VideoRotation::Clockwise90Degrees; 530 531 case Windows::Graphics::Display::DisplayOrientations::LandscapeFlipped: 532 return Windows::Media::Capture::VideoRotation::Clockwise180Degrees; 533 534 case Windows::Graphics::Display::DisplayOrientations::PortraitFlipped: 535 return (counterclockwise) ? Windows::Media::Capture::VideoRotation::Clockwise90Degrees: 536 Windows::Media::Capture::VideoRotation::Clockwise270Degrees ; 537 538 default: 539 return Windows::Media::Capture::VideoRotation::None; 540 } 541 } 542 543 void SDKSample::MediaCapture::AdvancedCapture::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) 544 { 545 try 546 { 547 create_task(m_mediaCaptureMgr->ClearEffectsAsync(Windows::Media::Capture::MediaStreamType::VideoPreview)).then([this](task<void> cleanTask) 548 { 549 m_bEffectAdded = true; 550 int index = EffectTypeCombo->SelectedIndex; 551 PropertySet^ props = ref new PropertySet(); 552 props->Insert(L"{698649BE-8EAE-4551-A4CB-3EC98FBD3D86}", index); 553 create_task(m_mediaCaptureMgr->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoPreview,"OcvTransform.OcvImageManipulations", props)).then([this](task<void> effectTask) 554 { 555 try 556 { 557 effectTask.get(); 558 559 auto mediaCapture = m_mediaCaptureMgr.Get(); 560 Windows::Media::Capture::VideoDeviceCharacteristic charecteristic = mediaCapture->MediaCaptureSettings->VideoDeviceCharacteristic; 561 562 ShowStatusMessage("Add effect successful to preview stream successful"); 563 if((charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::AllStreamsIdentical) && 564 (charecteristic != Windows::Media::Capture::VideoDeviceCharacteristic::PreviewRecordStreamsIdentical)) 565 { 566 Windows::Media::MediaProperties::IMediaEncodingProperties ^props = mediaCapture->VideoDeviceController->GetMediaStreamProperties(Windows::Media::Capture::MediaStreamType::VideoRecord); 567 Windows::Media::MediaProperties::VideoEncodingProperties ^videoEncodingProperties = static_cast<Windows::Media::MediaProperties::VideoEncodingProperties ^>(props); 568 if(!videoEncodingProperties->Subtype->Equals("H264")) //Cant add an effect to an H264 stream 569 { 570 task<void>(mediaCapture->AddEffectAsync(Windows::Media::Capture::MediaStreamType::VideoRecord,"OcvTransform.OcvImageManipulations", nullptr)).then([this](task<void> effectTask2) 571 { 572 try 573 { 574 effectTask2.get(); 575 ShowStatusMessage("Add effect successful to record stream successful"); 576 m_bEffectAddedToRecord = true; 577 AddEffectToImageStream(); 578 EffectTypeCombo->IsEnabled = true; 579 } 580 catch(Exception ^e) 581 { 582 ShowExceptionMessage(e); 583 EffectTypeCombo->IsEnabled = true; 584 } 585 }); 586 } 587 else 588 { 589 AddEffectToImageStream(); 590 EffectTypeCombo->IsEnabled = true; 591 } 592 593 } 594 else 595 { 596 AddEffectToImageStream(); 597 EffectTypeCombo->IsEnabled = true; 598 } 599 } 600 catch (Exception ^e) 601 { 602 ShowExceptionMessage(e); 603 EffectTypeCombo->IsEnabled = true; 604 } 605 }); 606 }); 607 } 608 catch (Platform::Exception ^e) 609 { 610 ShowExceptionMessage(e); 611 EffectTypeCombo->IsEnabled = true; 612 } 613 } 614