Created
August 27, 2011 17:47
-
-
Save MrGung/1175654 to your computer and use it in GitHub Desktop.
Disable exceptions in Visual Studio programamtically using F#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// list of exceptions that will be disabled in the script. | |
// if an exception is not yet known to Visual Studio the exception will be added to VS's list of exceptions automatically. | |
let exceptionsToDisable = [|"Microsoft.VisualStudio.TestTools.UnitTesting.AssertFailedException" | |
"System.Data.SqlClient.SqlException" | |
"System.IO.FileNotFoundException" | |
"System.IO.IOException" | |
"System.IO.PipeException" | |
"System.Net.WebException" | |
"System.NullReferenceException" | |
"System.Reflection.TargetInvocationException" | |
"System.Runtime.InteropServices.InvalidComObjectException" | |
"System.ServiceModel.CommunicationException" | |
"System.ServiceModel.EndpointNotFoundException"|] | |
// references | |
#r @"EnvDTE.dll" | |
#r @"EnvDTE80.dll" | |
#r @"EnvDTE90.dll" | |
open EnvDTE | |
open EnvDTE80 | |
open EnvDTE90 | |
open System | |
open System.Diagnostics | |
open System.Runtime.InteropServices | |
open System.Runtime.InteropServices.ComTypes | |
(* | |
In order to connect to the running VS-process its process-id must be known. | |
The following code determines that process-id. | |
The code was taken from http://fortysix-and-two.blogspot.com/2010/05/accessing-visual-studios-automation-api.html | |
Using VisualBasic the process-id is not necessary because VB automatically has access to the currently running instance of VS. | |
Since F# runs in a separate process (a child-process of the running instance of VS) the process-id of the parent VS-process must be determined. | |
*) | |
let getParentProcess (processId:int) = | |
let proc = Process.GetProcessById processId | |
let myProcID = new PerformanceCounter("Process", "ID Process", proc.ProcessName) | |
let myParentID = new PerformanceCounter("Process", "Creating Process ID", proc.ProcessName) | |
myParentID.NextValue() |> int | |
let currentProcess = Process.GetCurrentProcess().Id | |
let myVS = getParentProcess currentProcess | |
module Msdev = | |
[<DllImport("ole32.dll")>] | |
extern int GetRunningObjectTable([<In>]int reserved, [<Out>] IRunningObjectTable& prot) | |
[<DllImport("ole32.dll")>] | |
extern int CreateBindCtx([<In>]int reserved, [<Out>]IBindCtx& ppbc) | |
let tryFindInRunningObjectTable (name:string) = | |
//let result = new Dictionary<_,_>() | |
let mutable rot = null | |
if Msdev.GetRunningObjectTable(0,&rot) <> 0 then failwith "GetRunningObjectTable failed." | |
let mutable monikerEnumerator = null | |
rot.EnumRunning(&monikerEnumerator) | |
monikerEnumerator.Reset() | |
let mutable numFetched = IntPtr.Zero | |
let monikers = Array.init<ComTypes.IMoniker> 1 (fun _ -> null) | |
let mutable result = None | |
while result.IsNone && (monikerEnumerator.Next(1, monikers, numFetched) = 0) do | |
let mutable ctx = null | |
if Msdev.CreateBindCtx(0, &ctx) <> 0 then failwith "CreateBindCtx failed" | |
let mutable runningObjectName = null | |
monikers.[0].GetDisplayName(ctx, null, &runningObjectName) | |
if runningObjectName = name then | |
let mutable runningObjectVal = null | |
if rot.GetObject( monikers.[0], &runningObjectVal) <> 0 then failwith "GetObject failed" | |
result <- Some runningObjectVal | |
//result.[runningObjectName] <- runningObjectVal | |
result | |
let getVS2010ROTName id = | |
sprintf "!VisualStudio.DTE.10.0:%i" id | |
(* | |
The above code was all taken from someone else. Following some of my stuff. | |
Two functions are defined: | |
First, all exceptions will be enabled (which takes rather long - even when done via the GUI. | |
Then the exceptions from the list defined above will be disabled. | |
If an exception is not yet known to VS it will be made known to be able disable it. | |
*) | |
let enableAll (excSettings:EnvDTE90.ExceptionSettings) = | |
for excSetting in excSettings do | |
excSettings.SetBreakWhenThrown(false, excSetting) | |
let disableSelected (excSettings:EnvDTE90.ExceptionSettings) exceptionsToDisable = | |
for exceptionToDisble in exceptionsToDisable do | |
try | |
excSettings.SetBreakWhenThrown(false, (excSettings.Item exceptionToDisble)) | |
with | |
| :? System.Runtime.InteropServices.COMException -> | |
printfn "Error occurred disabling %s" exceptionToDisble | |
excSettings.SetBreakWhenThrown(false, excSettings.NewException(exceptionToDisble, 0u)) | |
// Instead of SetBreakWhenThrown it is also possible to SetBreakWhenUserUnhandled | |
// ------------------------------------------------------------------------------------------------------ | |
// Getting some objects from Visual Studio's object-model for automation... | |
let dte = (tryFindInRunningObjectTable (getVS2010ROTName myVS) |> Option.get) :?> DTE2 | |
let dbg = dte.Debugger :?> EnvDTE90.Debugger3 | |
let excSettings = dbg.ExceptionGroups.Item "Common Language Runtime Exceptions" | |
//enableAll excSettings; // commented out because it really takes long. | |
disableSelected excSettings exceptionsToDisable | |
printfn "Exceptions were disabled." | |
(* | |
Links: | |
http://msdn.microsoft.com/en-us/library/za2b25t3.aspx | |
http://books.google.de/books?id=21mIZpxyKz0C&pg=PA537&lpg=PA537&dq=%2B%22f%23%22+EnvDTE80&source=bl&ots=_jYg-zoGFA&sig=YlFK4sFMc-ZrHe6zEPrSqvi2N9s&hl=de#v=onepage&q=%2B%22f%23%22%20EnvDTE80&f=false | |
http://fortysix-and-two.blogspot.com/2010/05/accessing-visual-studios-automation-api.html | |
*) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment