- The error only happens in production (not in debugging).
- The error only happens on the first application run after Windows login.
- The error occurs when we click BtnUseDesktop and thus fire the BtnUseDesktop_Click event (below).
- The Event Viewer stack starts with the The.Application.Name.Main() method...
- but our code does not have that method (it's a WPF application).
Event Viewer
Application: The.Application.Name.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileNotFoundException
Stack:
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(
System.Object, System.Delegate, System.Object, Int32, System.Delegate)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(
System.Windows.Threading.DispatcherPriority, System.TimeSpan,
System.Delegate, System.Object, Int32)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr, Int32, IntPtr, IntPtr)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(System.Windows.Interop.MSG ByRef)
at System.Windows.Threading.Dispatcher.PushFrameImpl(
System.Windows.Threading.DispatcherFrame)
at System.Windows.Threading.Dispatcher.PushFrame(
System.Windows.Threading.DispatcherFrame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(System.Object)
at System.Windows.Application.RunInternal(System.Windows.Window)
at System.Windows.Application.Run(System.Windows.Window)
at The.Application.Name.Main()
BtnUseDesktop_Click
private void BtnUseDesktop_Click(object sender, RoutedEventArgs e)
{
AvSwitcher switcher = new AvSwitcher();
this.RunAsyncTask(() =>
switcher.SwitchToDesktop(this.windowSyncSvc.ActiveLyncWindowHandle));
}
The AvSwitcher that the Click Event Calls Into
public class AvSwitcher
{
private DeviceLocationSvc deviceLocationSvc;
private UIAutomationSvc uiAutomationSvc;
private WindowMovingSvc windowMovingSvc;
private ManualResetEvent manualResetEvent;
private Modality audioVideo;
public static bool IsSwitching { get; set; }
public AvSwitcher()
{
this.deviceLocationSvc = new DeviceLocationSvc();
this.uiAutomationSvc = new UIAutomationSvc();
this.windowMovingSvc = new WindowMovingSvc();
}
public void SwitchToDesktop(IntPtr activeLyncConvWindowHandle)
{
this.BeginHold(DeviceLocation.Desktop, activeLyncConvWindowHandle);
}
public void SwitchToWall(IntPtr activeLyncConvWindowHandle)
{
this.BeginHold(DeviceLocation.Wall, activeLyncConvWindowHandle);
}
private Conversation GetLyncConversation()
{
Conversation conv = null;
if (LyncClient.GetClient() != null)
{
conv = LyncClient.GetClient().ConversationManager.Conversations.FirstOrDefault();
}
return conv;
}
private void BeginHold(DeviceLocation targetLocation, IntPtr activeLyncConvWindowHandle)
{
AvSwitcher.IsSwitching = true;
// make sure the class doesn't dispose of itself
this.manualResetEvent = new ManualResetEvent(false);
Conversation conv = this.GetLyncConversation();
if (conv != null)
{
this.audioVideo = conv.Modalities[ModalityTypes.AudioVideo];
ModalityState modalityState = this.audioVideo.State;
if (modalityState == ModalityState.Connected)
{
this.HoldCallAndThenDoTheSwitching(targetLocation, activeLyncConvWindowHandle);
}
else
{
this.DoTheSwitching(targetLocation, activeLyncConvWindowHandle);
}
}
}
private void HoldCallAndThenDoTheSwitching(
DeviceLocation targetLocation,
IntPtr activeLyncConvWindowHandle)
{
try
{
this.audioVideo.BeginHold(
this.BeginHold_callback,
new AsyncStateValues()
{
TargetLocation = targetLocation,
ActiveLyncConvWindowHandle = activeLyncConvWindowHandle
});
this.manualResetEvent.WaitOne();
}
catch (UnauthorizedAccessException)
{
// the call is already on hold
this.DoTheSwitching(targetLocation, activeLyncConvWindowHandle);
}
}
private void BeginHold_callback(IAsyncResult ar)
{
if (ar.IsCompleted)
{
DeviceLocation targetLocation = ((AsyncStateValues)ar.AsyncState).TargetLocation;
IntPtr activeLyncConvWindowHandle =
((AsyncStateValues)ar.AsyncState).ActiveLyncConvWindowHandle;
this.DoTheSwitching(targetLocation, activeLyncConvWindowHandle);
}
Thread.Sleep(2000); // is this necessary
this.audioVideo.BeginRetrieve(this.BeginRetrieve_callback, null);
}
private void DoTheSwitching(DeviceLocation targetLocation, IntPtr activeLyncConvWindowHandle)
{
DeviceLocationSvc.TargetDevices targetDevices =
this.deviceLocationSvc.GetTargetDevices(targetLocation);
this.SwitchScreenUsingWinApi(targetDevices.Screen, activeLyncConvWindowHandle);
this.SwitchVideoUsingLyncApi(targetDevices.VideoDevice);
this.SwitchAudioUsingUIAutomation(
targetDevices.MicName,
targetDevices.SpeakersName,
activeLyncConvWindowHandle);
AvSwitcher.IsSwitching = false;
}
private void SwitchScreenUsingWinApi(Screen targetScreen, IntPtr activeLyncConvWindowHandle)
{
if (activeLyncConvWindowHandle != IntPtr.Zero)
{
WindowPosition wp =
this.windowMovingSvc.GetTargetWindowPositionFromScreen(targetScreen);
this.windowMovingSvc.MoveTheWindowToTargetPosition(activeLyncConvWindowHandle, wp);
}
}
private void SwitchVideoUsingLyncApi(VideoDevice targetVideoDevice)
{
if (targetVideoDevice != null)
{
LyncClient.GetClient().DeviceManager.ActiveVideoDevice = targetVideoDevice;
}
}
private void SwitchAudioUsingUIAutomation(
string targetMicName,
string targetSpeakersName,
IntPtr activeLyncConvWindowHandle)
{
if (targetMicName != null && targetSpeakersName != null)
{
AutomationElement lyncConvWindow =
AutomationElement.FromHandle(activeLyncConvWindowHandle);
AutomationElement lyncOptionsWindow =
this.uiAutomationSvc.OpenTheLyncOptionsWindowFromTheConvWindow(lyncConvWindow);
this.uiAutomationSvc.SelectTheTargetMic(lyncOptionsWindow, targetMicName);
this.uiAutomationSvc.SelectTheTargetSpeakers(lyncOptionsWindow, targetSpeakersName);
this.uiAutomationSvc.InvokeOkayButton(lyncOptionsWindow);
}
}
private void BeginRetrieve_callback(IAsyncResult ar)
{
this.audioVideo.EndRetrieve(ar);
this.manualResetEvent.Set(); // allow the program to exit
}
private class AsyncStateValues
{
internal DeviceLocation TargetLocation { get; set; }
internal IntPtr ActiveLyncConvWindowHandle { get; set; }
}
}
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…