CodedUI tests failing due to missing assembly reference? - visual-studio-2010

I have a coded UI test built with VS2010 for TFS2010 running on machine A. I have a test agent installed on machine A that the tests run on successfully. My testsettings file>Roles is set to RemoteExecution because these codedUI tests ALWAYS need to be run on machine A. The file always says "connected to the controller" that I specified.
I check the code into the build server (machine B), and it fails. With copy local set to false on the codedUI assemblies, the build fails with an error:
"Not runnable: Failed to initialize the unit test extension
'urn:CodedUITest': A unit test extension is not registered for the
following attribute:
Microsoft.VisualStudio.TestTools.UITesting.CodedUITestAttribute."
In the application logs on machine B, I get this:
(QTAgent32.exe, PID 5308, Thread 8) GetCollectorType: Failed to get
type for Collector
'Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo.SystemInfoDataCollector,
Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo,
Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a':
System.IO.FileNotFoundException: Could not load file or assembly
'Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo,
Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or
one of its dependencies. The system cannot find the file specified.
File name:
'Microsoft.VisualStudio.TestTools.DataCollection.SystemInfo,
Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean
throwOnError, Boolean ignoreCase, Boolean reflectionOnly,
StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean
loadTypeFromPartialName, ObjectHandleOnStack type) at
System.RuntimeTypeHandle.GetTypeByName(String name, Boolean
throwOnError, Boolean ignoreCase, Boolean reflectionOnly,
StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean
loadTypeFromPartialName) at System.RuntimeType.GetType(String
typeName, Boolean throwOnError, Boolean ignoreCase, Boolean
reflectionOnly, StackCrawlMark& stackMark) at
System.Type.GetType(String typeName, Boolean throwOnError) at
Microsoft.VisualStudio.TestTools.DataCollection.ExecutionPluginManager.GetCollectorType(String
collectorTypeName, Exception& loadException)
WRN: Assembly binding logging is turned OFF. To enable assembly bind
failure logging, set the registry value
[HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1. Note: There
is some performance penalty associated with assembly bind failure
logging. To turn this feature off, remove the registry value
[HKLM\Software\Microsoft\Fusion!EnableLog].
And in the Administration console I get this:
Following error encountered while reading sqm registry entry:
TF255003: The installation path cannot be found for the following
feature: ApplicationTier. Either the feature is not installed, or you
must use a different installation path.
With copy local set to true on the coded UI assemblies, I don't get any error in the Build Explorer in VS, but the build fails and says 0/0 tests run. In the application log on machine B, I get:
The description for Event ID 0 from source VSTTExecution cannot be
found. Either the component that raises this event is not installed on
your local computer or the installation is corrupted. You can install
or repair the component on the local computer.
If the event originated on another computer, the display information
had to be saved with the event.
The following information was included with the event:
(MSTest.exe, PID 5544, Thread 1) Exception thrown when enumerating
assembly:
Microsoft.VisualStudio.TestTools.Exceptions.EqtDataException: Unable
to load the test container
'C:\Builds\1\Project\Binaries\Microsoft.VisualStudio.QualityTools.CodedUITestFramework.dll'
or one of its dependencies. Error details:
System.IO.FileNotFoundException: Could not load file or assembly
'Microsoft.VisualStudio.QualityTools.Vsip, Version=10.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its
dependencies. The system cannot find the file specified.
at
Microsoft.VisualStudio.TestTools.TestTypes.Unit.AssemblyEnumerator.EnumerateAssembly(IWarningHandler
warningHandler, String location, ProjectData projectData, ObjectHandle
assemblyResolverWrapper) at
Microsoft.VisualStudio.TestTools.TestTypes.Unit.AssemblyEnumerator.EnumerateAssembly(IWarningHandler
warningHandler, String location, ProjectData projectData, ObjectHandle
assemblyResolverWrapper) at
Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestAttributeEnumerator.Read(ITestTypeExtensionClientSidesProvider
provider, IWarningHandler warningHandler, String assemblyFileName,
ProjectData projectData, TestRunConfiguration testRunConfiguration)
Machine B does have VS2010 express installed.
What else do I need to do to get this building on Machine B (build machine), but tests running on Machine A (with the test agent)? What else can I do to diagnose this?
UPDATE: I tried manually copying the qualitytools.vsip dll into the project and referencing it that way with copy local set to true, but now I'm back to getting
"Failed to initialize the unit test extension 'urn:CodedUITest': A
unit test extension is not registered for the following attribute:
Microsoft.VisualStudio.TestTools.UITesting.CodedUITestAttribute."

Kindly make a check the project property that the target framework is not set to .NET framework 4 client profile. Instead set to .Net framework 4 (without client profile)

using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UITesting.HtmlControls;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodedUITestProject1.Libraries
{
class generic
{
public static BrowserWindow mParentWindow { get; set; }
public static BrowserWindow ParentWindow
{
get
{
if(mParentWindow==null)
{ mParentWindow = TopParentWindow(); }
return mParentWindow;
}
}
public static BrowserWindow TopParentWindow()
{
BrowserWindow window = new BrowserWindow();
window.SearchProperties[UITestControl.PropertyNames.ClassName]=BrowserWindow.CurrentBrowser.ToString();
return window;
}
public enum PropertyType
{ Id,
Name,
ClassName,
InnerText,
TagInstance
}
public static void EnterText<T>(PropertyType type,string propvalue,string text) where T:HtmlControl
{
HtmlControl genericControl = (T)Activator.CreateInstance(typeof(T), new object[] { ParentWindow });
if (type==PropertyType.Id)
{
genericControl.SearchProperties[HtmlControl.PropertyNames.Id] = propvalue;
}
else if (type == PropertyType.Id)
{
genericControl.SearchProperties[HtmlControl.PropertyNames.Id] = propvalue;
}
Keyboard.SendKeys(genericControl, text);
}
public static void ClickLink<T>(PropertyType type, string propvalue) where T : HtmlControl
{
HtmlControl genericControl = (T)Activator.CreateInstance(typeof(T), new object[] { ParentWindow });
if (type == PropertyType.Id)
{
genericControl.SearchProperties[HtmlControl.PropertyNames.Id] = propvalue;
}
else if (type == PropertyType.Id)
{
genericControl.SearchProperties[HtmlControl.PropertyNames.Id] = propvalue;
}
//Assert.IsTrue(genericControl.WaitForControlExist(40000));
Mouse.Click(genericControl);
}
public static Boolean ExistLink<T>(PropertyType type, string propvalue) where T : HtmlControl
{
HtmlControl genericControl = (T)Activator.CreateInstance(typeof(T), new object[] { ParentWindow });
if (type == PropertyType.Id)
{
genericControl.SearchProperties[HtmlControl.PropertyNames.Id] = propvalue;
}
else if (type == PropertyType.Id)
{
genericControl.SearchProperties[HtmlControl.PropertyNames.Id] = propvalue;
}
try
{
Assert.IsTrue(genericControl.WaitForControlExist(4000));
return true;
}
catch (Exception e)
{
return false;
}
//Mouse.Click(genericControl);
}
}
}

Solution 1: Replace the name as that seen in pop UP. Might be this code can help clicking it
WinWindow pop = new WinWindow(null);
pop.SearchProperties.Add("Name", "Message from webpage", "ClassName", "#32770");
‘Windows Internet Explorer
pop.TechnologyName = "MSAA";
pop.DrawHighlight();
//------------
“Usinng MSTEST.exe to generate result”
C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE>MSTest /testcontainer:
D:\Practise\CodedUITestProject1\CodedUITestProject1\CodedUITestProject1\bin\Debu
g\CodedUITestProject1.dll /test:CodedUITestMethod1 /resultsfile:D:\SachintestRes
.trx
public void CodedUITestMethod1()
{
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
string testcase = " /testcontainer:" + "D:\\Practise\\CodedUITestProject1\\CodedUITestProject1\\CodedUITestProject1\\bin\\Debug\\CodedUITestProject1.dll /test:CodedUITestMethod1 /resultsfile:D:\\SachintestResAut.trx";
string Path = #"C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE\MSTest";
Process myProcess = new Process();
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(Path, testcase);
myProcessStartInfo.UseShellExecute = false;
try
{
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
myProcess.BeginOutputReadLine();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
WinText text = new WinText(pop);
text.SearchProperties.Add("Name", "Some Name");
String msg = text.GetProperty("DisplayText").ToString();
if (msg.Contains("Data saved."))
{
Console.WriteLine("System is displaying " + msg);
}
else
{
Console.WriteLine("System is displaying " + msg);
}
WinButton ok = new WinButton(pop);
ok.TechnologyName = "MSAA";
ok.SearchProperties.Add("Name", "OK");
Mouse.Click(ok);
Solution 2: Try the Browser Dialog Actions like OK,Cancel,Close .May be it can be helpful. PFB snapshot below.
try
{
BrowserWindow browserWindow = new BrowserWindow();
browserWindow.PerformDialogAction(BrowserDialogAction.Ok);
}
catch (Exception)
{
// If a popup does not exists and an error is thrown, continue...
Playback.PlaybackSettings.ContinueOnError = true;
}
//C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE>MSTest /testcontainer:
D:\Practise\CodedUITestProject1\CodedUITestProject1\CodedUITestProject1\bin\Debu
g\CodedUITestProject1.dll /test:CodedUITestMethod1 /resultsfile:D:\SachintestRes
.trx
public void CodedUITestMethod1()
{
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
// To generate code for this test, select "Generate Code for Coded UI Test" from the shortcut menu and select one of the menu items.
string testcase = " /testcontainer:" + "D:\\Practise\\CodedUITestProject1\\CodedUITestProject1\\CodedUITestProject1\\bin\\Debug\\CodedUITestProject1.dll /test:CodedUITestMethod1 /resultsfile:D:\\SachintestResAut.trx";
string Path = #"C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE\MSTest";
Process myProcess = new Process();
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(Path, testcase);
myProcessStartInfo.UseShellExecute = false;
try
{
myProcess.StartInfo = myProcessStartInfo;
myProcess.Start();
myProcess.BeginOutputReadLine();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

Related

Visual Studio Resources: Default Location for Add Existing File

In the Visual Studio Resources area, is there a way to set the default location in the file select dialog, when selecting "Add Existing File..."?
The default location, when clicking on that menu is:
C:\Program Files (x86)\Microsoft\Visual Studio\2017\Enterprise\Common7\IDE
True, it is a small thing, as selecting my Downloads folder or something else is easy, but I keep having to go somewhere else, usually my Downloads folder, and it would definitely save time to have the default location go somewhere else.
I know that the Open File common dialog, which Visual Studio uses, has the option in the initial structure to specify the initial (default) directory, so the only question is, if it is possible for the default directory to point somewhere else.
I am using Visual Studio 2017.
You can use my Visual Commander extension to monitor for the Resources.AddExistingFile command and set your preferred directory before its execution. See the following C# extension example:
public class E : VisualCommanderExt.IExtension
{
public void SetSite(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package)
{
events = DTE.Events;
commandEvents = events.get_CommandEvents(null, 0);
commands = DTE.Commands as EnvDTE80.Commands2;
commandEvents.BeforeExecute += OnBeforeExecute;
}
public void Close()
{
commandEvents.BeforeExecute -= OnBeforeExecute;
}
private void OnBeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
{
string name = GetCommandName(Guid, ID);
if (name == "Resources.AddExistingFile")
System.IO.Directory.SetCurrentDirectory(#"c:\downloads");
}
private string GetCommandName(string Guid, int ID)
{
if (Guid == null)
return "null";
try
{
return commands.Item(Guid, ID).Name;
}
catch (System.Exception)
{
}
return "";
}
private EnvDTE.Events events;
private EnvDTE.CommandEvents commandEvents;
private EnvDTE80.Commands2 commands;
}

TypeLoadException: Could not load type from assembly in Xamarin

I have Xamarin Forms PCL application and I am trying to inherit from HttpContent in attempt to follow this reference. I would like to implement progress bar for image upload. Here is my implementation which contains minimum code to implement HttpContent:
public class ProgressableStreamContent : HttpContent
{
public ProgressableStreamContent()
{ }
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return Task.Run(async () =>
{
});
}
protected override bool TryComputeLength(out long length)
{
length = 0;
return true;
}
}
and I have procedure that is using this ProgressableStreamContent:
public async void UseProgressableStreamContent()
{
var progressableContent = new ProgressableStreamContent();
}
Problem is that this code produces exception:
UNHANDLED EXCEPTION: System.TypeLoadException: Could not load type 'MyApp.Classes.ProgressableStreamContent' from assembly 'MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
When I comment out line "var progressableContent = new ProgressableStreamContent();" - everything works good.
When I comment out inheritance ": HttpContent" (and override keywords) - everything works good.
Should I install some package? What else could be a problem?
I resolved issue by changing profile from 259 to 7. Changing profile includes deleting all NuGet packages and installing them again after profile change.

How to debug Windows Service Applications?

I'm creating a Windows Service Application in Visual Studio 2010 Ultimate SP1.
I was following 'How to' from MSDN:
http://msdn.microsoft.com/en-us/library/7a50syb3.aspx
I have encountered two problems:
I cannot start a service via Server Explorer - my service is listed there, but in the context menu I have only two options available: Refresh and Properties. There is no "Start" though MSDN documentation says that there should be that option.
Fortunately, I can avoid this hassle by using Services Control Manager.
The next step is: "In Visual Studio, choose Processes from the Debug menu".
That option doesn't exist in Debug menu. I have only "Attach to Process", but services aren't listed there.
Does somebody know what is wrong and how I am supposed to debug my application?
Thank you in advance.
As a thought: I have built a lot of Windows services and for one of many reasons, I do not create the core code in the service itself. The service is essentially the "operational layer", if you will. Creating the core code in a dll permits debugging and testing of that particular code. You can create a console or desktop app that will run the core code which can be used during development and testing phases.
Personally, I created a service runner application which captures logging in conjunction with the start and stop functionality. My OnStart and OnStop code blocks are literally identical to that of the service.
Next, when you test the service, you should be able to start the service (e.g. myService.exe) and attach to process. However, another note is that you should pause/wait the service thread (for say 30 seconds) with a debug build so you have time to attach to the process and you don't miss your initialization code. Just remember, you have to install your service then start via the Windows service manager.
Here is some code you that might point you in the direction that I use. In the service program.cs file I use the below; then in the Service OnStart() method you call your dll and run. Also, you can stop your service, replace the dll with an updated version then restart. With C# you can replace the service exe as well, but these are only C# characteristics: in C++ you cannot.
static class Program
{
public const string SERVICE_NAME = "myService";
public const string SERVICE_DISPLAY_NAME = "My Service";
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (args != null && args.Length > 0)
{
foreach (string arg in args)
{
switch (arg.ToLower())
{
case "-install":
ManageService(true);
return;
case "-remove":
ManageService(false);
return;
}
}
}
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service()
};
ServiceBase.Run(ServicesToRun);
}
private static void ManageService(bool bInstall)
{
string parms;
if (bInstall == true)
{
parms = string.Format("Create {0} type= own start= demand binPath= \"{1}\" DisplayName= \"{2}\"", SERVICE_NAME,
System.Reflection.Assembly.GetExecutingAssembly().Location, SERVICE_DISPLAY_NAME);
}
else // remove
{
parms = string.Format("Delete {0}", SERVICE_NAME);
}
try
{
string output = string.Empty;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo("sc.exe", parms);
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
proc.StartInfo = startInfo;
proc.Start();
output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(10000);
if (proc.HasExited == true)
{
// NOTE: The project type has been changed from Windows Service to Console Application
// so that Console.WriteLine will output to the console
Console.WriteLine(output);
}
else
{
proc.Close();
Console.WriteLine("Timed out waiting to install service");
}
}
catch (System.ComponentModel.Win32Exception)
{
Console.WriteLine("Unable to locate sc.exe");
}
}
}
//From the main function a method from service class can be called like below code
//DebugApp method can be called from main and so the service can be debug:
//Service class
public partial class CServices : ServiceBase
{
public CServices()
{
InitializeComponent();
}
**public void DebugApp()
{
OnStart(new string[]{});
}**
protected override void OnStart(string[] args)
{
System.Console.WriteLine("Testing");
System.Console.Read();
}
protected override void OnStop()
{
}
}
//Calling from main:
static void Main()
{
Services1.CServices uc = new CServices();
uc.DebugApp();
}

C#5 AsyncCtp BadImageFormatException

Please help me with this one, I've been writing a console applicaiton using the AsyncCtpLibrary and the C#5 ctp compiler. First time I got to actually running a code which awaits, I got this:
System.BadImageFormatException was unhandled
Message=An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
Source=AsyncCtpLibrary
StackTrace:
Server stack trace:
at [...].<Execute>d__1c.MoveNext()
at [...].Execute()
at [...].<Move>d__1d.MoveNext() in[..]:line 266
Exception rethrown at [0]:
at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.<SetException>b__1(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
InnerException:
Am I missing a dll to be referenced?
important new stuff
My failing method looks like this:
public async override Task<bool> Execute()
{
//do stuff
await stuff;
//do other stuff
await base.Execute()
//do other stuff
return true;
}
I've followed Jon Skeet's advice trying to recreate the mistake little by little, and now I can tell that the await base.Execute() line is the killer! If I comment that line out, everything runs, if I leave it in, calling my method fails IMMEDIATELY (not when reaching the base.Execute()). So I assume the ctp compiler does something freaky. Why? What should I never do? How big is the bug?
old stuff:
EDIT:
As for 32bit/64bit issue, my system is 32bit (inside a virtual machine, mind you), and as far as I know AsyncCtpLibrary.dll doesn't contain unmanaged code. All my projects (class libraries and single console app) all have build tabs like this:
What can possibly be still wrong?
EDIT:
I also checked the Fusion log viewer, the AsyncCtpLibrary is loaded without any error:
*** Assembly Binder Log Entry (6/10/2011 # 9:04:11 PM) ***
The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe
--- A detailed error log follows.
=== Pre-bind state information ===
LOG: User = WIN-N74LV38NLV3\Daver
LOG: DisplayName = AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
(Fully-specified)
LOG: Appbase = file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyApp.exe
Calling assembly : MyLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\MyApp.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///C:/Users/Daver/Documents/Visual Studio 2010/Projects/[...]/bin/Debug/AsyncCtpLibrary.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: AsyncCtpLibrary, Version=1.0.4107.18181, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: Binding succeeds. Returns assembly from C:\Users\Daver\Documents\Visual Studio 2010\Projects\[...]\bin\Debug\AsyncCtpLibrary.dll.
LOG: Assembly is loaded in default load context.
I also checked the IL code of the <Execute>d__1c compiler-generated class' MoveNext() method, and the only assemblies it references ([assemblyName]) are mscorlib, System.Core, and AsyncCtpLibrary.
I checked the manifest of both my dll and AsyncCtpLibrary, mine said .corflags 0x00000003 // ILONLY 32BITREQUIRED, AsyncCtpLibrary said .corflags 0x00000009 // ILONLY, I'm unsure if this can be the problem.
Please help, I'm out of ideas!
EDIT: I've heard back from the compiler team, who have confirmed it as a bug. It had already been fixed in their codebase, so hopefully we'll see that fix in the next release / beta / CTP. The fix isn't going to be back-ported to "normal" VS2010 as it's a pretty unusual set of circumstances, at least before async.
EDIT: Okay, I've now got a really short but complete program which demonstrates the problem. I believe it's a mixture of generics and calling a base method:
using System;
using System.Threading.Tasks;
public abstract class AsyncAction<T>
{
public virtual Task<T> Execute()
{
// We never get this far
Console.WriteLine("Execute called");
return null;
}
}
public class BoolAction : AsyncAction<bool>
{
public async override Task<bool> Execute()
{
return await base.Execute();
}
}
class Test
{
static void Main()
{
BoolAction b = new BoolAction();
b.Execute();
}
}
EDIT: Okay, I've come up with a workaround. Basically, to call the base class method non-virtually, the compiler creates a synthetic method in BoolAction. It gets that slightly wrong, but we can get it right:
public class BoolAction : AsyncAction<bool>
{
public async override Task<bool> Execute()
{
return await BaseExecute();
}
private Task<bool> BaseExecute()
{
return base.Execute();
}
}
So whenever you were writing base.Execute, write BaseExecute and insert that extra method. It's not too bad a workaround, until the team fix the bug.
EDIT: I've simplified the example a bit - you don't need any overrides, and in particular you don't need the base class to expose a Task<T>. A call to any virtual base.Foo method will do it:
public abstract class AsyncAction<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class BoolAction : AsyncAction<bool>
{
#pragma warning disable 1998 // We're not awaiting anything
public async void Execute()
{
base.GetT();
}
#pragma warning restore 1998
}
class Test
{
static void Main()
{
BoolAction b = new BoolAction();
b.Execute();
}
}
EDIT: Contrary to my previous thoughts, this does affect iterators as well. No async CTP required...
public abstract class Base<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class Derived : Base<bool>
{
public System.Collections.IEnumerator Foo()
{
base.GetT();
yield break;
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
d.Foo().MoveNext();
}
}
EDIT: And it affects anonymous functions too...
using System;
public abstract class Base<T>
{
public virtual T GetT()
{
return default(T);
}
}
public class Derived : Base<bool>
{
public void Foo()
{
Action x = () => base.GetT();
x();
}
}
class Test
{
static void Main()
{
Derived d = new Derived();
d.Foo();
}
}
You are hitting known VS 2010 bug
https://connect.microsoft.com/VisualStudio/feedback/details/626550/badimageformatexception-on-simple-program-using-generics-and-lambdas
This exception often occurs when you try and load a 32 bit DLL in a 64 bit environment.
If you are running on a 64 bit OS try changing your projects settings to compile directly for x86 (rather than AnyCPU).
(This might sound backwards, but it's because if you are loading an external 32 bit DLL you need to force your whole project to be 32 bit.)

How do I write to the Visual Studio Output Window in My Custom Tool?

I am writing a custom tool and I currently have it doing what I want as far as functionality. I would like to be able to write to Visual Studio if something goes wrong. (Incorrectly formatted code or whatever).
Are there any standards for this? Right now I basically can force the tool to fail and Visual Studio puts in a warning that it has done so. I'd like a category in the Output window with any resulting messages I want to send. I could also live with a more descriptive task/warning in the Error list window.
Output Window
To write to the "General" output window in Visual Studio, you need to do the following:
IVsOutputWindow outWindow = Package.GetGlobalService( typeof( SVsOutputWindow ) ) as IVsOutputWindow;
Guid generalPaneGuid = VSConstants.GUID_OutWindowGeneralPane; // P.S. There's also the GUID_OutWindowDebugPane available.
IVsOutputWindowPane generalPane;
outWindow.GetPane( ref generalPaneGuid , out generalPane );
generalPane.OutputString( "Hello World!" );
generalPane.Activate(); // Brings this pane into view
If, however, you want to write to a custom window, this is what you need to do:
IVsOutputWindow outWindow = Package.GetGlobalService( typeof( SVsOutputWindow ) ) as IVsOutputWindow;
// Use e.g. Tools -> Create GUID to make a stable, but unique GUID for your pane.
// Also, in a real project, this should probably be a static constant, and not a local variable
Guid customGuid = new Guid("0F44E2D1-F5FA-4d2d-AB30-22BE8ECD9789");
string customTitle = "Custom Window Title";
outWindow.CreatePane( ref customGuid, customTitle, 1, 1 );
IVsOutputWindowPane customPane;
outWindow.GetPane( ref customGuid, out customPane);
customPane.OutputString( "Hello, Custom World!" );
customPane.Activate(); // Brings this pane into view
Details on IVsOutputWindow and IVsOutputWindowPane can be found on MSDN.
Error List
For adding items to the error list, the IVsSingleFileGenerator has a method call void Generate(...) which has a parameter of the type IVsGeneratorProgress. This interface has a method void GeneratorError() which lets you report errors and warnings to the Visual Studio error list.
public class MyCodeGenerator : IVsSingleFileGenerator
{
...
public void Generate( string inputFilePath, string inputFileContents, string defaultNamespace, out IntPtr outputFileContents, out int output, IVsGeneratorProgress generateProgress )
{
...
generateProgress.GeneratorError( false, 0, "An error occured", 2, 4);
...
}
...
}
The details of GeneratorError() can be found on MSDN.
There is another way using Marshal.GetActiveObject to grab a running DTE2 instance.
First reference EnvDTE and envdte80. This currently works in VisualStudio 2012, I haven't tried the others yet.
using System;
using System.Runtime.InteropServices;
using EnvDTE;
using EnvDTE80;
internal class VsOutputLogger
{
private static Lazy<Action<string>> _Logger = new Lazy<Action<string>>( () => GetWindow().OutputString );
private static Action<string> Logger
{
get { return _Logger.Value; }
}
public static void SetLogger( Action<string> logger )
{
_Logger = new Lazy<Action<string>>( () => logger );
}
public static void Write( string format, params object[] args)
{
var message = string.Format( format, args );
Write( message );
}
public static void Write( string message )
{
Logger( message + Environment.NewLine );
}
private static OutputWindowPane GetWindow()
{
var dte = (DTE2) Marshal.GetActiveObject( "VisualStudio.DTE" );
return dte.ToolWindows.OutputWindow.ActivePane;
}
}
If you want anything to appear in the Output window, it has to come from stdout. To do this, your app needs to be linked as a "console" app. Set the /SUBSYSTEM:CONSOLE flag in the project's property page, under Linker/System set the SubSystem property to CONSOLE.
Once you have your output in the window, if you include the text "Error:" it will appear as an error, or if you set "Warning:" it will appear as a warning. If your error text begins with a path/filename, followed by a line number in parenthesis, the IDE will recognize it as a "clickable" error, and navigate you automatically to the faulting line.
This is demonstrated in the following helper class from a Microsoft sample project:
https://github.com/microsoft/VSSDK-Extensibility-Samples/blob/df10d37b863feeff6e8fcaa6f4d172f602a882c5/Reference_Services/C%23/Reference.Services/HelperFunctions.cs#L28
The code is as follows:
using System;
using System.Diagnostics;
using Microsoft.VisualStudio.Shell.Interop;
namespace Microsoft.Samples.VisualStudio.Services
{
/// <summary>
/// This class is used to expose some utility functions used in this project.
/// </summary>
internal static class HelperFunctions
{
/// <summary>
/// This function is used to write a string on the Output window of Visual Studio.
/// </summary>
/// <param name="provider">The service provider to query for SVsOutputWindow</param>
/// <param name="text">The text to write</param>
internal static void WriteOnOutputWindow(IServiceProvider provider, string text)
{
// At first write the text on the debug output.
Debug.WriteLine(text);
// Check if we have a provider
if (null == provider)
{
// If there is no provider we can not do anything; exit now.
Debug.WriteLine("No service provider passed to WriteOnOutputWindow.");
return;
}
// Now get the SVsOutputWindow service from the service provider.
IVsOutputWindow outputWindow = provider.GetService(typeof(SVsOutputWindow)) as IVsOutputWindow;
if (null == outputWindow)
{
// If the provider doesn't expose the service there is nothing we can do.
// Write a message on the debug output and exit.
Debug.WriteLine("Can not get the SVsOutputWindow service.");
return;
}
// We can not write on the Output window itself, but only on one of its panes.
// Here we try to use the "General" pane.
Guid guidGeneral = Microsoft.VisualStudio.VSConstants.GUID_OutWindowGeneralPane;
IVsOutputWindowPane windowPane;
if (Microsoft.VisualStudio.ErrorHandler.Failed(outputWindow.GetPane(ref guidGeneral, out windowPane)) ||
(null == windowPane))
{
if (Microsoft.VisualStudio.ErrorHandler.Failed(outputWindow.CreatePane(ref guidGeneral, "General", 1, 0)))
{
// Nothing to do here, just debug output and exit
Debug.WriteLine("Failed to create the Output window pane.");
return;
}
if (Microsoft.VisualStudio.ErrorHandler.Failed(outputWindow.GetPane(ref guidGeneral, out windowPane)) ||
(null == windowPane))
{
// Again, there is nothing we can do to recover from this error, so write on the
// debug output and exit.
Debug.WriteLine("Failed to get the Output window pane.");
return;
}
if (Microsoft.VisualStudio.ErrorHandler.Failed(windowPane.Activate()))
{
Debug.WriteLine("Failed to activate the Output window pane.");
return;
}
}
// Finally we can write on the window pane.
if (Microsoft.VisualStudio.ErrorHandler.Failed(windowPane.OutputString(text)))
{
Debug.WriteLine("Failed to write on the Output window pane.");
}
}
}
}
You can use the Debug and/or Trace classes. There is some information here:
http://msdn.microsoft.com/en-us/library/bs4c1wda(VS.71).aspx
Best of luck.
use System.Diagnostics.Debugger.Message

Resources