Visual Studio 2010 AddIn DTE2 not working - visual-studio-2010

I am trying to create an AddIn in Visual Studio 2010 like below:
public void OnConnection(object application, ext_ConnectMode
connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
EnvDTE80.Windows2 wins2obj;
AddIn addinobj;
object ctlobj = null;
Window newWinobj;
// A toolwindow must be connected to an add-in, so this line
// references one.
addinobj = _applicationObject.AddIns.Item(1);
wins2obj = (Windows2)_applicationObject.Windows;
// This section specifies the path and class name of the windows
// control that you want to host in the new tool window, as well as
// its caption and a unique GUID.
string assemblypath = "C:\\temp\\WindowsControlLibrary1.dll";
string classname = "WindowsControlLibrary1.UserControl1";
string guidpos = "{426E8D27-3D33-4FC8-B3E9-9883AADC679F}";
string caption = "CreateToolWindow2 Test";
// Create the new tool window and insert the user control in it.
newWinobj = wins2obj.CreateToolWindow2(addinobj, assemblypath,
classname, caption, guidpos, ref ctlobj);
newWinobj.Visible = true;
}
Now I need to pass DTE2 to the newly created object inside the window (ctlobj). If I declare a public variable in ctlobj and set it here, Visual studio crashes and I get this exception:
COM Exception was unhandled
Invalid index. (Exception from HRESULT: 0x8002000B (DISP_E_BADINDEX))
. Any ideas ???
Thanks!!

There a workaround though:
// Get an instance of the currently running Visual Studio IDE.
EnvDTE80.DTE2 dte2;
dte2 = (EnvDTE80.DTE2)System.Runtime.InteropServices.Marshal.
GetActiveObject("VisualStudio.DTE.10.0");

I know you have the answer from Nazaf, there is another way, it is a little bit cleaner. Make the dte object a public property in your addin class and pass the addin class to the newWinObj.
Then your newWinObj will have access to both the addin and the dte objects. It works, I use this system.

Related

ItemEvent in SAP B1 SDK with a SAP form created in Visual Studio 2015

I truly really need your help.
I want to be able to deal with a Click on an Item on my Form which has been created in Visual Studio 2015
this is my Main Methode :
static void Main(string[] args)
{
try
{
Application oApp = null;
if (args.Length < 1)
{
oApp = new Application();
}
else
{
oApp = new Application(args[0]);
}
Menu MyMenu = new Menu();
MyMenu.AddMenuItems();
oApp.RegisterMenuEventHandler(MyMenu.SBO_Application_MenuEvent);
Application.SBO_Application.AppEvent += new SAPbouiCOM._IApplicationEvents_AppEventEventHandler(SBO_Application_AppEvent);
oApp.Run();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
and this code is automatically generated by Visual studio when i creat a new SAP B1 Project.
now i want to add an ItemEvent to handle some klick events on some Forms.
when i add this to the code :
Application.SBO_Application.ItemEvent += new SAPbouiCOM._IApplicationEvents_ItemEventEventHandler(SBO_Application_ItemEvent);
und of course the Methode SBO_Application_ItemEvent then i got a compiler error in this code line that an object reference is requiered for non-static fields...
what did i miss?
I just want to be able to do something when the User clicks on the Grid in my Form.
A Method to add a click event to a grid on a custom user form,
using Visual Studio and SAP BUSINESS ONE STUDIO:
Open the .b1f file in visual studio designer.
an example form:
Click on the Grid you wish to add the event for and navigate to the properties window
Click the lightening symbol to see the events
Double click the space next to your Desired Event
visual studio should then add the code for the event as required, something similar to the below should appear in code:
private void docRowGrid_ClickBefore(object sboObject, SAPbouiCOM.SBOItemEventArg
pVal, ref bool BubbleEvent)
{
}

Can one rename a source file using Roslyn APIs?

I'm trying to write a UnmatchedClassAndFilename diagnostic and code fix using the new Roslyn and Visual Studio API's. The idea is to rename a class or filename in case they aren't equal.
How can I use the Roslyn API to rename a file in Visual Studio? The Workspace class doesn't seem to support this.
Update: Created an issue at CodePlex (https://roslyn.codeplex.com/workitem/258)
No, there is no current support for this in the Workspaces API. It's a common request but I'm not sure we have something explicitly tracking that work, so feel free to file the bug on CodePlex.
I am using Visual Studio 2017 and the Code Refactoring VSIX project template to accomplish this.
Here is my code:
private async Task<Solution> ConvertTypeNameToPascalCaseAsync(Document document, TypeDeclarationSyntax typeDecl, CancellationToken cancellationToken)
{
// Produce a PascalCased version of the type declaration's identifier token.
var identifierToken = typeDecl.Identifier;
var newName = identifierToken.Text.ToPascalCase();
// Get the symbol representing the type to be renamed.
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
var typeSymbol = semanticModel.GetDeclaredSymbol(typeDecl, cancellationToken);
// Produce a new solution that has all references to that type renamed, including the declaration.
var originalSolution = document.Project.Solution;
var optionSet = originalSolution.Workspace.Options;
var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, typeSymbol, newName, optionSet, cancellationToken).ConfigureAwait(false);
var newDocId = DocumentId.CreateNewId(document.Project.Id);
var newText = await newSolution.GetDocument(document.Id).GetTextAsync(cancellationToken).ConfigureAwait(false);
// rename document by adding a new document with the new name and removing the old document
newSolution = newSolution.AddAdditionalDocument(newDocId, newName + ".cs", newText);
newSolution = newSolution.RemoveDocument(document.Id);
// Return the new solution with the now PascalCased type name.
return newSolution;
}
Note: ToPascalCase() is an extension method that I added to the string class.
The major point to notice is that I used AddAdditionalDocument() and RemoveDocument() to effectively rename the existing document to match my new name.
Here is the code that sets up the Code Refactoring engine:
public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
{
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
// Find the node at the selection.
var node = root.FindNode(context.Span);
// Only offer a refactoring if the selected node is a type declaration node.
var typeDecl = node as TypeDeclarationSyntax;
if (typeDecl == null)
{
return;
}
if (typeDecl.Identifier.Text.IsUpper())
{
// For any type declaration node, create a code action to reverse the identifier text.
var action = CodeAction.Create("Convert type name to PascalCase", c => ConvertTypeNameToPascalCaseAsync(context.Document, typeDecl, c));
// Register this code action.
context.RegisterRefactoring(action);
}
}
Note: IsUpper() is also an extension method that I added to the string class.
Incidentally, my specific use case is to convert all caps class names with underscores in them to PascalCased class names. Examples:
TEST = Test
TEST_CLASS = TestClass
TEST_A_CLASS = TestAClass

How to automate Package Manager Console in Visual Studio 2013

My specific problem is how can I automate "add-migration" in a build process for the Entity Framework. In researching this, it seems the mostly likely approach is something along the lines of automating these steps
Open a solution in Visual Studio 2013
Execute "Add-Migration blahblah" in the Package Manager Console (most likely via an add-in vsextention)
Close the solution
This initial approach is based on my own research and this question, the powershell script ultimately behind Add-Migration requires quite a bit of set-up to run. Visual Studio performs that setup automatically when creating the Package Manager Console and making the DTE object available. I would prefer not to attempt to duplicate that setup outside of Visual Studio.
One possible path to a solution is this unanswered stack overflow question
In researching the NuGet API, it does not appear to have a "send this text and it will be run like it was typed in the console". I am not clear on the lines between Visual Studio vs NuGet so I am not sure this is something that would be there.
I am able to find the "Pacakage Manager Console" ironically enough via "$dte.Windows" command in the Package Manager Console but in a VS 2013 window, that collection gives me objects which are "Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase". If there is a way stuff text into it, I think I need to get it to be a NuGetConsole.Implementation.PowerConsoleToolWindow" through reviewing the source code I am not clear how the text would stuffed but I am not at all familiar with what I am seeing.
Worst case, I will fall back to trying to stuff keys to it along the lines of this question but would prefer not to since that will substantially complicate the automation surrounding the build process.
All of that being said,
Is it possible to stream commands via code to the Package Manager Console in Visual Studio which is fully initialized and able to support an Entity Framework "add-migration" command?
Thanks for any suggestions, advice, help, non-abuse in advance,
John
The approach that worked for me was to trace into the entity framework code starting in with the AddMigrationCommand.cs in the EntityFramework.Powershell project and find the hooks into the EntityFramework project and then make those hooks work so there is no Powershell dependency.
You can get something like...
public static void RunIt(EnvDTE.Project project, Type dbContext, Assembly migrationAssembly, string migrationDirectory,
string migrationsNamespace, string contextKey, string migrationName)
{
DbMigrationsConfiguration migrationsConfiguration = new DbMigrationsConfiguration();
migrationsConfiguration.AutomaticMigrationDataLossAllowed = false;
migrationsConfiguration.AutomaticMigrationsEnabled = false;
migrationsConfiguration.CodeGenerator = new CSharpMigrationCodeGenerator(); //same as default
migrationsConfiguration.ContextType = dbContext; //data
migrationsConfiguration.ContextKey = contextKey;
migrationsConfiguration.MigrationsAssembly = migrationAssembly;
migrationsConfiguration.MigrationsDirectory = migrationDirectory;
migrationsConfiguration.MigrationsNamespace = migrationsNamespace;
System.Data.Entity.Infrastructure.DbConnectionInfo dbi = new System.Data.Entity.Infrastructure.DbConnectionInfo("DataContext");
migrationsConfiguration.TargetDatabase = dbi;
MigrationScaffolder ms = new MigrationScaffolder(migrationsConfiguration);
ScaffoldedMigration sf = ms.Scaffold(migrationName, false);
}
You can use this question to get to the dte object and from there to find the project object to pass into the call.
This is an update to John's answer whom I have to thank for the "hard part", but here is a complete example which creates a migration and adds that migration to the supplied project (project must be built before) the same way as Add-Migration InitialBase -IgnoreChanges would:
public void ScaffoldedMigration(EnvDTE.Project project)
{
var migrationsNamespace = project.Properties.Cast<Property>()
.First(p => p.Name == "RootNamespace").Value.ToString() + ".Migrations";
var assemblyName = project.Properties.Cast<Property>()
.First(p => p.Name == "AssemblyName").Value.ToString();
var rootPath = Path.GetDirectoryName(project.FullName);
var assemblyPath = Path.Combine(rootPath, "bin", assemblyName + ".dll");
var migrationAssembly = Assembly.Load(File.ReadAllBytes(assemblyPath));
Type dbContext = null;
foreach(var type in migrationAssembly.GetTypes())
{
if(type.IsSubclassOf(typeof(DbContext)))
{
dbContext = type;
break;
}
}
var migrationsConfiguration = new DbMigrationsConfiguration()
{
AutomaticMigrationDataLossAllowed = false,
AutomaticMigrationsEnabled = false,
CodeGenerator = new CSharpMigrationCodeGenerator(),
ContextType = dbContext,
ContextKey = migrationsNamespace + ".Configuration",
MigrationsAssembly = migrationAssembly,
MigrationsDirectory = "Migrations",
MigrationsNamespace = migrationsNamespace
};
var dbi = new System.Data.Entity.Infrastructure
.DbConnectionInfo("ConnectionString", "System.Data.SqlClient");
migrationsConfiguration.TargetDatabase = dbi;
var scaffolder = new MigrationScaffolder(migrationsConfiguration);
ScaffoldedMigration migration = scaffolder.Scaffold("InitialBase", true);
var migrationFile = Path.Combine(rootPath, migration.Directory,
migration.MigrationId + ".cs");
File.WriteAllText(migrationFile, migration.UserCode);
var migrationItem = project.ProjectItems.AddFromFile(migrationFile);
var designerFile = Path.Combine(rootPath, migration.Directory,
migration.MigrationId + ".Designer.cs");
File.WriteAllText(designerFile, migration.DesignerCode);
var designerItem = project.ProjectItems.AddFromFile(migrationFile);
foreach(Property prop in designerItem.Properties)
{
if (prop.Name == "DependentUpon")
prop.Value = Path.GetFileName(migrationFile);
}
var resxFile = Path.Combine(rootPath, migration.Directory,
migration.MigrationId + ".resx");
using (ResXResourceWriter resx = new ResXResourceWriter(resxFile))
{
foreach (var kvp in migration.Resources)
resx.AddResource(kvp.Key, kvp.Value);
}
var resxItem = project.ProjectItems.AddFromFile(resxFile);
foreach (Property prop in resxItem.Properties)
{
if (prop.Name == "DependentUpon")
prop.Value = Path.GetFileName(migrationFile);
}
}
I execute this in my project template's IWizard implementation where I run a migration with IgnoreChanges, because of shared entites with the base project. Change scaffolder.Scaffold("InitialBase", true) to scaffolder.Scaffold("InitialBase", false) if you want to include the changes.

Show ErrorList Windows in Visual Studio 2010 Addin

I have Win7 64 bits, Visual Studio 2010, and I have developed an Addin for Vs2010.
I try show messages in Error List Windows VS.
I use ErrorListProvider in OnBuildProjConfigDone build event for Addin
this._buildEvents.OnBuildProjConfigDone += new _dispBuildEvents_OnBuildProjConfigDoneEventHandler(_buildEvents_OnBuildProjConfigDone);
I get this error InvalidOperationException
The service 'Microsoft.VisualStudio.Shell.Interop.IVsTaskList' must be
installed for this feature to work. Ensure that this service is
available.
Connect
public partial class Connect : IDTExtensibility2, IDTCommandTarget, System.Windows.Forms.IWin32Window, IOleCommandTarget
OnBuildProjConfigDone
void _buildEvents_OnBuildProjConfigDone(string project, string projectConfig, string platform, string solutionConfig, bool success)
{
// Omitted
if (!resul)
{
project.DTE.ExecuteCommand("Build.Cancel");
var errorListHelper = new ErrorListHelper();
ErrorListProvider errorProvider = errorListHelper.GetErrorListProvider();
var newError = new ErrorTask();
newError.ErrorCategory = TaskErrorCategory.Message;
newError.Category = TaskCategory.BuildCompile;
newError.Text = "Cualquier mensaje de error aqui";
errorProvider.Tasks.Add(newError);
}
}
ErrorListHelper
public class ErrorListHelper : System.IServiceProvider
{
public ErrorListProvider GetErrorListProvider()
{
ErrorListProvider provider = new ErrorListProvider(this);
provider.ProviderName = "Provider";
provider.ProviderGuid = System.Guid.NewGuid();
return provider;
}
public object GetService(Type serviceType)
{
return Package.GetGlobalService(serviceType);
}
}
Suggestion by #JohnL: I put a breakpoint in my GetService method and Package.GetGlobalService is returning null.
Any suggestions?
Ryan Molden (MSFT) says:
Package.GetGlobalService is relying on at least one MPF package (from
the specific version of MPF you are referencing) having been loaded.
Since you yourself are an AddIn not a Package you can't guarantee that
in any way.
You should pass something like new
ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider))) as the argument to ErrorListProvide
Package.GetGlobalService is returning null.
I use this code in my Addin. I test it and I get not error, and I can show errors and warnings in ErrorList Windows VS. I'll testing more for safely.
public partial class Connect
{
ErrorListProvider _errorListProvider = null;
void CreateErrorListProvider()
{
if (_errorListProvider == null)
{
System.IServiceProvider serviceProvider = new ServiceProvider(_applicationObject as Microsoft.VisualStudio.OLE.Interop.IServiceProvider);
_errorListProvider = new ErrorListProvider(serviceProvider);
_errorListProvider.ProviderName = "custom Errors";
_errorListProvider.ProviderGuid = new Guid("xxxxxxxxxxxxxx");
}
}

Testing SharePoint List Workflow from Visual Studio 2010

I am trying to create a custom workflow in Visual Studio 2010 for SharePoint 2010 and have run into a problem. I have figured out how to deploy the workflow to the SharePoint site, but executing it results in an error. However, the error message is completely non-descriptive, so I want to find out if there is a way to execute it from Visual Studio so I can see where it fails, and possibly why.
I'm trying to simply create a new subsite based on a given ListItem.Title information.
How is it you go about debugging?
For reference, here is my code
class CreateSubsite : System.Workflow.ComponentModel.Activity
{
protected override System.Workflow.ComponentModel.ActivityExecutionStatus
Execute(System.Workflow.ComponentModel.ActivityExecutionContext executionContext)
{
createSite();
return System.Workflow.ComponentModel.ActivityExecutionStatus.Closed;
}
public void createSite()
{
using (SPSite currentSite = SPContext.Current.Site)
{
using (SPWeb currentWeb = SPContext.Current.Web)
{
SPList currentList = SPContext.Current.List;
SPListItem currentListItem = SPContext.Current.ListItem;
WorkflowContext workflow = new WorkflowContext();
SPSite parentSite = new SPSite(workflow.CurrentWebUrl);
SPWeb newSite = currentSite.AllWebs.Add(
currentListItem.Title.Replace(" ", "_"),
currentListItem.Title,
String.Empty, currentWeb.Language, "CI Template", false, false
);
}
}
}
}
Try to remove Using keyword from your code .You should not dispose your SPSite and SPWeb when you use SPContext because disposing of that object might actually break the workflow as it may still need a reference to that object for later use.
just rewrite your code without use using
public void createSite() {
SPSite currentSite = SPContext.Current.Site
SPWeb currentWeb = SPContext.Current.Web
//.... Rest of your code
Hope that help
Regards.

Resources