2015-06-05 21:48:04 +00:00
namespace VitaliiGanzha.VsDingExtension
2014-03-13 22:21:47 +00:00
{
2015-06-05 21:48:04 +00:00
using System ;
using System.Diagnostics ;
2015-06-12 21:09:04 +00:00
using System.Drawing ;
2015-06-05 21:48:04 +00:00
using System.Globalization ;
using System.Media ;
using System.Runtime.InteropServices ;
2015-06-12 21:09:04 +00:00
using System.Windows.Forms ;
2015-06-05 21:48:04 +00:00
using EnvDTE ;
using EnvDTE80 ;
using Microsoft.VisualStudio.ComponentModelHost ;
using Microsoft.VisualStudio.Shell ;
using Microsoft.VisualStudio.TestWindow.Extensibility ;
using Process = System . Diagnostics . Process ;
2014-03-13 22:21:47 +00:00
[PackageRegistration(UseManagedResourcesOnly = true)]
2015-06-05 22:02:21 +00:00
[InstalledProductRegistration("#110", "#112", "1.1", IconResourceID = 400)]
2014-03-13 22:21:47 +00:00
[Guid(GuidList.guidVsDingExtensionProjectPkgString)]
2014-03-20 23:28:02 +00:00
[ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")]
2015-06-01 01:02:52 +00:00
[ProvideOptionPage(typeof(OptionsDialog), "Ding", "Options", 0, 0, true)]
2015-06-08 19:05:20 +00:00
public sealed class VsDingExtensionProjectPackage : Package , IDisposable
2014-03-13 22:21:47 +00:00
{
private DTE2 applicationObject ;
private AddIn addInInstance ;
2014-03-22 00:03:52 +00:00
private BuildEvents buildEvents ;
private DebuggerEvents debugEvents ;
private SoundPlayer buildCompleteSoundPlayer ;
private SoundPlayer debugSoundPlayer ;
private SoundPlayer testCompleteSoundPlayer ;
2015-06-05 21:48:04 +00:00
private OptionsDialog _options = null ;
2015-06-01 01:02:52 +00:00
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow ( ) ;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId ( IntPtr handle , out int processId ) ;
2014-03-13 22:21:47 +00:00
public VsDingExtensionProjectPackage ( )
{
2015-06-01 01:02:52 +00:00
Debug . WriteLine ( string . Format ( CultureInfo . CurrentCulture , "Entering constructor for: {0}" , ToString ( ) ) ) ;
2014-03-13 22:21:47 +00:00
}
#region Package Members
protected override void Initialize ( )
{
2015-06-01 01:02:52 +00:00
Debug . WriteLine ( string . Format ( CultureInfo . CurrentCulture , "Entering Initialize() of: {0}" , ToString ( ) ) ) ;
2014-03-13 22:21:47 +00:00
base . Initialize ( ) ;
2014-03-22 00:03:52 +00:00
buildCompleteSoundPlayer = new SoundPlayer ( Resources . build ) ;
debugSoundPlayer = new SoundPlayer ( Resources . debug ) ;
testCompleteSoundPlayer = new SoundPlayer ( Resources . ding ) ;
2014-03-25 05:40:05 +00:00
applicationObject = ( DTE2 ) GetService ( typeof ( DTE ) ) ;
2015-06-01 01:02:52 +00:00
buildEvents = applicationObject . Events . BuildEvents ;
debugEvents = applicationObject . Events . DebuggerEvents ;
2014-03-13 22:21:47 +00:00
2015-06-01 01:02:52 +00:00
buildEvents . OnBuildDone + = ( scope , action ) = >
{
2015-06-12 21:09:04 +00:00
if ( Options . IsBeepOnBuildComplete )
{
HandleEventSafe ( buildCompleteSoundPlayer , "Build has been completed." ) ;
}
2015-06-01 01:02:52 +00:00
} ;
2015-06-12 21:09:04 +00:00
2014-03-25 05:40:05 +00:00
debugEvents . OnEnterBreakMode + = delegate ( dbgEventReason reason , ref dbgExecutionAction action )
{
2015-06-12 21:09:04 +00:00
if ( reason ! = dbgEventReason . dbgEventReasonStep & & Options . IsBeepOnBreakpointHit )
2014-03-25 05:40:05 +00:00
{
2015-06-12 21:09:04 +00:00
HandleEventSafe ( debugSoundPlayer , "Breakpoint was hit." ) ;
2014-03-25 05:40:05 +00:00
}
} ;
2014-03-13 22:21:47 +00:00
2014-03-20 23:28:02 +00:00
var componentModel =
2015-06-01 01:02:52 +00:00
GetGlobalService ( typeof ( SComponentModel ) ) as IComponentModel ;
2014-03-13 22:21:47 +00:00
2014-03-20 23:28:02 +00:00
if ( componentModel = = null )
{
2014-03-22 00:03:52 +00:00
Debug . WriteLine ( "componentModel is null" ) ;
return ;
2014-03-20 23:28:02 +00:00
}
var operationState = componentModel . GetService < IOperationState > ( ) ;
operationState . StateChanged + = OperationStateOnStateChanged ;
2014-03-13 22:21:47 +00:00
}
2014-03-20 23:28:02 +00:00
2015-06-05 21:48:04 +00:00
private OptionsDialog Options
{
get
{
if ( _options = = null )
{
_options = ( OptionsDialog ) GetDialogPage ( typeof ( OptionsDialog ) ) ;
}
return _options ;
}
}
2015-06-12 21:09:04 +00:00
private void HandleEventSafe ( SoundPlayer soundPlayer , string messageText )
{
PlaySoundSafe ( soundPlayer ) ;
ShowNotifyMessage ( messageText ) ;
}
private void ShowNotifyMessage ( string messageText )
{
if ( ! _options . ShowTrayNotifications )
{
return ;
}
string autoAppendMessage = System . Environment . NewLine + "You can disable this notification in:" + System . Environment . NewLine + "Tools->Options->Ding->Show tray notifications" ;
messageText = string . Format ( "{0}{1}" , messageText , autoAppendMessage ) ;
System . Threading . Tasks . Task . Run ( async ( ) = >
{
var tray = new NotifyIcon
{
Icon = SystemIcons . Application ,
BalloonTipIcon = ToolTipIcon . Info ,
BalloonTipText = messageText ,
BalloonTipTitle = "Visual Studio Ding extension" ,
Visible = true
} ;
tray . ShowBalloonTip ( 5000 ) ;
await System . Threading . Tasks . Task . Delay ( 5000 ) ;
tray . Icon = ( Icon ) null ;
tray . Visible = false ;
tray . Dispose ( ) ;
} ) ;
}
private void PlaySoundSafe ( SoundPlayer soundPlayer )
2014-03-25 05:40:05 +00:00
{
2015-06-05 21:48:04 +00:00
if ( ShouldPlaySound ( ) )
2015-06-01 01:02:52 +00:00
{
2015-06-04 18:42:54 +00:00
try
{
soundPlayer . Play ( ) ;
}
catch ( Exception ex )
{
ActivityLog . LogError ( GetType ( ) . FullName , ex . Message ) ;
}
2014-03-25 05:40:05 +00:00
}
}
2015-06-05 21:48:04 +00:00
private bool ShouldPlaySound ( )
2014-03-20 23:28:02 +00:00
{
2015-06-12 21:09:04 +00:00
if ( ! Options . IsBeepOnlyWhenVisualStudioIsInBackground )
2014-03-20 23:28:02 +00:00
{
2015-06-05 21:48:04 +00:00
return true ;
2014-03-20 23:28:02 +00:00
}
2015-06-12 21:09:04 +00:00
return Options . IsBeepOnlyWhenVisualStudioIsInBackground & & ! ApplicationIsActivated ( ) ;
2014-03-20 23:28:02 +00:00
}
2014-03-13 22:21:47 +00:00
2015-06-05 21:48:04 +00:00
private void OperationStateOnStateChanged ( object sender , OperationStateChangedEventArgs operationStateChangedEventArgs )
2015-06-01 01:02:52 +00:00
{
2015-06-12 21:09:04 +00:00
if ( Options . IsBuildOnTestComplete & & operationStateChangedEventArgs . State . HasFlag ( TestOperationStates . TestExecutionFinished ) )
2015-06-05 21:48:04 +00:00
{
2015-06-12 21:09:04 +00:00
HandleEventSafe ( testCompleteSoundPlayer , "Test execution has been completed." ) ;
2015-06-05 21:48:04 +00:00
}
2015-06-01 01:02:52 +00:00
}
2015-06-05 21:48:04 +00:00
#endregion
2015-06-04 18:42:54 +00:00
2015-06-12 21:09:04 +00:00
private bool ApplicationIsActivated ( )
2015-06-01 01:02:52 +00:00
{
var activatedHandle = GetForegroundWindow ( ) ;
if ( activatedHandle = = IntPtr . Zero )
{
return false ; // No window is currently activated
}
var procId = Process . GetCurrentProcess ( ) . Id ;
int activeProcId ;
GetWindowThreadProcessId ( activatedHandle , out activeProcId ) ;
2015-06-04 18:42:54 +00:00
return activeProcId = = procId ;
2015-06-01 01:02:52 +00:00
}
2015-06-08 19:05:20 +00:00
public void Dispose ( )
{
SafeDispose ( this . debugSoundPlayer ) ;
SafeDispose ( this . buildCompleteSoundPlayer ) ;
SafeDispose ( this . testCompleteSoundPlayer ) ;
}
private void SafeDispose ( SoundPlayer soundPlayer )
{
try
{
soundPlayer . Dispose ( ) ;
}
catch ( Exception ex )
{
ActivityLog . LogError ( this . GetType ( ) . FullName , "Error when disposing player: " + ex . Message ) ;
}
}
2014-03-13 22:21:47 +00:00
}
}