How do you programmatically run Static Code Analysis in Visual Studio 2017? - visual-studio

I'm working on a solution to localize legacy applications. I've written a Visual studio add-in using EnvDte that automates the process of setting the "Localizable" flag for every form in the solution to true, which is a critical step for extracting resources on form designers. I am now trying to deal with any text that is set programmatically, text that trigger the Globalization (CA13##) warnings.
designer.Visible = true;
var host = (IDesignerHost)designer.Object;
var provider = TypeDescriptor.GetProvider(host.RootComponent);
var typeDescriptor = provider.GetExtendedTypeDescriptor(host.RootComponent);
if (typeDescriptor == null)
continue;
var propCollection = typeDescriptor.GetProperties();
var propDesc = propCollection["Localizable"];
if (propDesc != null && host.RootComponent != null &&
(bool?)propDesc.GetValue(host.RootComponent) != true)
{
try
{
propDesc.SetValue(host.RootComponent, true);
}
catch (Exception ex)
{
// log the error
}
// save changes
}
I've been able to run it manually from the menu using: Analyze -> Run Code Analysis -> On Solution to get a list of issues, but I would like to automate this step with another add-in that runs and extracts the results.
Are there any resources that point to accessing the build warnings or the results of the code analysis?
Are there any solutions that already do this using EnvDte or Roslyn?

Ok, I've managed to glean enough information to put together the add-in. Put simply, you use _dte.ExecuteCommand()
Initialize the command:
// nothing to see here...
_package = package ?? throw new ArgumentNullException(nameof(package));
var commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (commandService == null)
return;
_dte = (DTE2)ServiceProvider.GetService(typeof(DTE));
var menuCommandId = new CommandID(CommandSet, CommandId);
var menuItem = new MenuCommand(MenuItemCallback, menuCommandId);
commandService.AddCommand(menuItem);
_events = _dte.Events.BuildEvents;
// since static code analysis is a sort of build you need to hook into OnBuildDone
_events.OnBuildDone += OnBuildDone;
Trigger the analysis
private void MenuItemCallback(object sender, EventArgs e)
{
_dte.ExecuteCommand("Build.RunCodeAnalysisonSolution");
}
Extract errors in the OnBuildDone event
private void OnBuildDone(vsBuildScope scope, vsBuildAction action)
{
Dispatcher.CurrentDispatcher.InvokeAsync(new Action(() =>
{
_dte.ExecuteCommand("View.ErrorList", " ");
var errors = _dte.ToolWindows.ErrorList.ErrorItems;
for (int i = 1; i <= errors.Count; i++)
{
ErrorItem error = errors.Item(i);
var code = error.Collection.Item(1);
var item = new
{
error.Column,
error.Description,
error.ErrorLevel,
error.FileName,
error.Line,
error.Project
};
error.Navigate(); // you can navigate to the error if you wanted to.
}
});
}

Related

Player Notifications with Xamarin MediaManager plugin

I'm using the media manager nuget plugin and it's great, but for the life of me, I can't get the lock screen or car bluetooth to show the notifications. I'm using the following to display the notifications (set within OnAppearing)
ViewModel.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "RadioSchedule":
if (listData != null)
{
listData.ItemsSource = null;
var first = ViewModel.RadioSchedule[0];
Device.BeginInvokeOnMainThread(() =>
{
listData.ItemsSource = ViewModel.RadioSchedule;
MediaFile.Metadata.Artist = MediaFile.Metadata.DisplaySubtitle = MediaFile.Metadata.AlbumArtist = first.Artist;
MediaFile.Metadata.Title = MediaFile.Metadata.DisplayTitle = first.Track;
MediaFile.Metadata.DisplayIcon = new Image { Source = "icon".CorrectedImageSource() };
MediaFile.Metadata.BluetoothFolderType = "1";
MediaFile.Type = MediaFileType.Audio;
MediaFile.Url = Constants.RadioStream;
MediaFile.Availability = ResourceAvailability.Remote;
MediaFile.MetadataExtracted = true;
MediaFile.Metadata.Date = DateTime.Now;
MediaFile.Metadata.Duration = 300;
MediaFile.Metadata.Genre = "Rock";
MediaFile.Metadata.TrackNumber = MediaFile.Metadata.NumTracks = 1;
MediaFile.Metadata.DisplayDescription = "Radio Station";
if (!ViewModel.NotificationStarted)
{
if (CrossMediaManager.Current.MediaNotificationManager != null)
CrossMediaManager.Current.MediaNotificationManager.StartNotification(MediaFile);
ViewModel.NotificationStarted = true;
}
CrossMediaManager.Current.MediaNotificationManager?.UpdateNotifications(MediaFile, MediaPlayerStatus.Playing);
});
}
break;
The code itself is being hit (I can set break points and they are hit). I've tried it on and off the UI thread as well.
The playlist comes from a webapi which works fine. The notifier gives unknown/unknown on the device media player (both iOS and Android) and nothing in-car. For Android, the permissions the readme file says to use have also been set.
Is there some sort of magic I have to do to get this to work? This is a Xam.Forms package rather than something native.
The MediaPlayer is started further in the class using the following code
CrossMediaManager.Current.Play(Constants.RadioStream, MediaFileType.Audio, ResourceAvailability.Remote);
Where Constants.RadioStream is the URL of the radio stream.

Silverlight app freezes on Mac when file saved

Pretty simple code to launch SaveFileDialog and then save data.
Opens prompt, I can select where I save, it saves file and then whole tab/app freezes. Obviously works fine on Windows/IE. Any suggestions?
private void SavePDFFile()
{
var saveFileDialog = new SaveFileDialog
{
DefaultExt = "pdf",
Filter = string.Format("Document(.{0})|*.{0}", "pdf"),
FilterIndex = 1,
DefaultFileName = DateTime.Now.ToString("HHmmMMddyyyy")
};
var saveClicked = saveFileDialog.ShowDialog();
if (!saveClicked.HasValue || !saveClicked.Value) return;
var fileStream = saveFileDialog.OpenFile();
try
{
this.IsBusy = true;
fileStream.Write(this.PDFData, 0, this.PDFData.Length);
fileStream.Close();
}
catch (Exception ex)
{
this.DisplayErrorMessage("Error saving PDF file", ex);
}
finally
{
this.IsBusy = false;
}
}
Answering my own question. This is nothing to do with code itself. It is security issue. In order to allow this code to execute on Mac (and it seems new versions of IE as well) you need to give it more permissions.
On IE you need to add website to list of Trusted sites.
On Mac - you need to set Silverlight to run in "Unsafe" mode. This is in Preferences/Security/Silverlight and need to select website, hold "Option" key and then open dropdown to see that option. Took a while to find it..
#katit I also faced this issue while working on a Silverlight OOB application.. my app was working fine in Windows but in Mac it got freezed and I have to force quit to use it again.
I was actually reading a PDF (stored in field type - 'varbinary') from server and storing it to user's local machine.
The solution worked for me is to download file chunks in parts (I used buffer size - 1 MB).
Not sure what file size you are using when your application gets freeze.. but I think, writing 'PDFData' to filestream in small parts may help you.
Also, add filestream.Flush(); (see highlighted in below code) in your code and see if this helps:
private void SavePDFFile()
{
var saveFileDialog = new SaveFileDialog
{
DefaultExt = "pdf",
Filter = string.Format("Document(.{0})|*.{0}", "pdf"),
FilterIndex = 1,
DefaultFileName = DateTime.Now.ToString("HHmmMMddyyyy")
};
var saveClicked = saveFileDialog.ShowDialog();
if (!saveClicked.HasValue || !saveClicked.Value) return;
var fileStream = saveFileDialog.OpenFile();
try
{
this.IsBusy = true;
fileStream.Write(this.PDFData, 0, this.PDFData.Length);
**filestream.Flush();**
fileStream.Close();
}
catch (Exception ex)
{
this.DisplayErrorMessage("Error saving PDF file", ex);
}
finally
{
this.IsBusy = false;
}
}

Windows 8.1 store apps OnCommandsRequested doesn't add ApplicationCommands when async used

On the App.xaml.cs I have the following code
private async void OnCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs e)
{
var loader = ResourceLoader.GetForCurrentView();
var generalCommand = new SettingsCommand("General Settings", "General Settings", handler =>
{
var generalSettings = new GeneralSettingsFlyout();
generalSettings.Show();
});
e.Request.ApplicationCommands.Add(generalCommand);
object data;
IAuthService _authService = new AuthService();
if (Global.UserId == 0)
data = await _authService.GetSettingValueBySettingName(DatabaseType.GeneralDb, ApplicationConstants.GeneralDbSettingNames.ShowSupportInfo);
else
data = await _authService.GetSettingValueBySettingName(DatabaseType.UserDb, ApplicationConstants.UserDbSettingNames.ShowSupportInfo);
if (data != null && data.ToString().Equals("1"))
{
var supportCommand = new SettingsCommand("Support", "Support", handler =>
{
var supportPane = new SupportFlyout();
supportPane.Show();
});
e.Request.ApplicationCommands.Add(supportCommand);
}
var aboutCommand = new SettingsCommand("About", loader.GetString("Settings_OptionLabels_About"), handler =>
{
var aboutPane = new About();
aboutPane.Show();
});
e.Request.ApplicationCommands.Add(aboutCommand);
}
This code adds the setting "General Settings" but neither "Support" or "About" commands. Can anyone advice what's wrong with this code?
Instead of querying the commands from your service when they are requested you'll need to query them ahead of time and then add the already known commands.
You cannot use await in OnCommandsRequested.
A method returns when it gets to the first await, so only commands added to the request before the await will be used.
Since the SettingsPaneCommandsRequestedEventArgs doesn't provide a deferral there is no way to tell the requester to wait for internal async calls to complete.
Note also that SettingsPane is deprecated and not recommended for new app development for Windows 10.

How to wait unitl the build command is over in the Visual Studio Add-In?

I want to create a Visual Studio add-in that times the build.
Here is my code so far:
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if(commandName == "BuildCurrentSolution.Connect.BuildCurrentSolution")
{
var window = _applicationObject.Windows.Item(Constants.vsWindowKindOutput);
var outputWindow = (OutputWindow)window.Object;
OutputWindowPane outputWindowPane = null;
for (var i = 1; i <= outputWindow.OutputWindowPanes.Count; i++)
{
if (outputWindow.OutputWindowPanes.Item(i).Name.Equals("BuildCurrentSolution", StringComparison.CurrentCultureIgnoreCase))
{
outputWindowPane = outputWindow.OutputWindowPanes.Item(i);
break;
}
}
if (outputWindowPane == null)
{
outputWindowPane = outputWindow.OutputWindowPanes.Add("BuildCurrentSolution");
}
outputWindowPane.OutputString("The build has started.\n");
var sw = new Stopwatch();
sw.Start();
_applicationObject.ExecuteCommand("Build.BuildSolution");
sw.Stop();
outputWindowPane.OutputString(string.Format("The build has ended. Elapsed time: {0} seconds.\n", sw.Elapsed.TotalSeconds));
handled = true;
}
}
}
Unfortunately, it does not do what I want it to, because _applicationObject.ExecuteCommand returns immediately.
Is it possible to wait for the completion of the command or better yet is there an event which is fired when the command is over?
Alternatively, maybe there is a different way to run the build command, the one allowing to wait or be notified when the build is over.
I was probably too eager to create this question.
Automating Visual Studio instance from separate process contains the answer. I should use _applicationObject.Solution.SolutionBuild.Build(true); instead of _applicationObject.ExecuteCommand("Build.BuildSolution");.
That's it.

Is there a Visual Studio 2010 file preview tab plugin?

Is there a Visual Studio 2010 plugin for the new "preview tab" feature in Visual Studio 2012?
I've tried to do it by myself, but I have no expierience in doing VS extensions nor using EnvDTE API.
I've followed Building and publishing an extension for Visual Studio 2010 to create a new Visual Studio 2010 extension.
Then I added a Tools menu item with the VSPackage Builder designer, and used this code to try to imitate the behaviour.
I am not able to:
Determine whenever a file is selected, so I have to do a loop.
Open a file in already existing window.
Change the window to be shown
at the right.
I leave the code here, just in case someone else is interested on creating an extension. Hope (s)he has a better knowledge of VS Extensibility.
[Guid(GuidList.guidPreviewDocumentTabPkgString)]
public class PreviewDocumentTabPackage : PreviewDocumentTabPackageBase
{
private DTE dte;
private Document currentTab;
protected override void Initialize()
{
base.Initialize();
this.dte = this.GetService(typeof(_DTE)) as DTE;
if (this.dte == null)
{
throw new ArgumentNullException("dte");
}
var applicationObject = (DTE2)GetGlobalService(typeof(SDTE));
var solutionExplorer = applicationObject.ToolWindows.SolutionExplorer;
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
object currentItem = null;
while (true) // To be improved
{
// Get selected items
var items = solutionExplorer.SelectedItems as Array;
// Only do logic if there is one file selected, no preview for multiple files.
if (items != null &&
items.Length == 1)
{
var item = items.GetValue(0);
if (currentItem == null)
{
currentItem = item;
}
else
{
// Only show preview if the file is "new".
if (item != currentItem)
{
currentItem = item;
// Determine if is a c# file.
var realItem = (UIHierarchyItem)currentItem;
var itemName = realItem.Name;
if (itemName.EndsWith(".cs"))
{
// Get the file
var projectItem = (ProjectItem)realItem.Object;
var projectItemPath = projectItem.Properties.Item("FullPath")
.Value.ToString();
// No already opened file.
if (currentTab == null)
{
// Open the file and get the window.
this.currentTab = this.dte.Documents.Open(projectItemPath);
}
else
{
// Todo: Open the file in the this.currentTab window.
}
}
}
}
}
// Avoid flooding
System.Threading.Thread.Sleep(100);
}
});
}
}

Resources