How to programmatically add a custom component to Visual Studio toolbox? - c#

I am creating an installer for a custom SSIS component that we have written. I would like to add the custom component automatically, rather than asking the user to manually add it.
I'm trying to do this with this code:
public void AddToolboxItem(string toolboxTabName, string toolBoxItemName, string toolBoxItemPath) {
Type dteReference;
EnvDTE.ToolBox toolBox;
EnvDTE80.ToolBoxItem2 addedToolBoxItem;
// Get a reference to the visual studio development environment.
dteReference = Type.GetTypeFromProgID("VisualStudio.DTE.9.0");
if(dteReference != null) {
// Get a reference to the toolbox of the development environment.
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)Activator.CreateInstance(dteReference);
toolBox = (EnvDTE.ToolBox)dte.Windows.Item("{B1E99781-AB81-11D0-B683-00AA00A3EE26}").Object;
// Loop through all tab pages to find the toolbox tab page that was specified
// in the toolboxTabName parameter.
foreach (EnvDTE80.ToolBoxTab2 toolBoxTab in toolBox.ToolBoxTabs) {
// Is this the right toolbox?
if(string.Compare(toolBoxTab.Name, toolboxTabName, true) == 0) {
// First check if the component is not already in the toolbox:
bool found = false;
foreach(EnvDTE80.ToolBoxItem2 toolBoxItem in toolBoxTab.ToolBoxItems) {
if (string.Compare(toolBoxItem.Name, toolBoxItemName, true) == 0) {
found = true;
break;
}
}
// The toolbox item is not in the toolbox tab, add it:
if (!found) {
addedToolBoxItem = (EnvDTE80.ToolBoxItem2)toolBoxTab.ToolBoxItems.Add(
toolBoxItemName,
toolBoxItemPath,
EnvDTE.vsToolBoxItemFormat.vsToolBoxItemFormatDotNETComponent);
}
break;
}
}
}
}
I can get a reference to the "Data Flow Transformations" ToolBox Tab, but adding an item fails without an exception or error.
I call this function with the parameters:
toolboxTabName = "Data Flow Transformations"
toolBoxItemName = "Special Test Component"
toolBoxItemPath = "c:\Program Files\Microsoft SQL Server\100\DTS\PipelineComponents\mdTest.dll"
As a sanity check, I tried using the vsToolBoxItemFormatDotNETComponent enumeration as Add()'s third parameter. This causes Add to return a valid object (ie, success), but the new item does not appear on the tool box. I suspect there is some sort of 'save' operation that may be necessary (even if I get the Add() to work properly).
Is there any way to programmatically add a SSIS component to the
toolbox?

Same question can also be found in the MSDN forums and it has been answered there by an MVP, Moderator. I am pasting the link to the answer provided in MSDN forums so that others stumbling on this question can know what the answer is.
Programmatically Add an SSIS Component to the Toolbox (social.msdn.microsoft.com)

Related

Intercepting standard "Save All" Visual Studio command

I am writing the functionality of a deprecated VS Addin into a Package extension for VS 2015.
In the package extension there is a tool window with a toolbar containing some buttons which execute commands. Amongst these, there is a 'Save All' button, which should not only save the files of the solution to the local disk, but also save the files back to the database to which the user is connected. This works fine at present. However, the user will probably click on the standard Visual Studio 'Save All' button, and expect the files to be written to the database as well. So I need to intercept the standard 'Save All' command and add my method that handles the saving of the files to the database.
I managed to do this, but it is just not as neat as I think it should be. I'm not knowledgeable regarding events and delegates. I read up about it, and then I don't use it often enough, and then I forget what I read and so on.
So the functionality for the 'Save All' toolbar button in the package extension is found as follows in the Package.cs file. In the Initialize method:
protected override void Initialize()
{
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (null != mcs)
{
CommandID saveAllCommandID = new CommandID(new Guid(Guids.guidConnectCommandPackageCmdSet), (int)PkgCmdIDList.cmdidSaveAllCommand);
command = new OleMenuCommand(new EventHandler(SaveAllCommandCallback), saveAllCommandID);
command.BeforeQueryStatus += BeforeQueryStatusCallback;
mcs.AddCommand(command);
}
visualStudioInstance = (DTE2)this.ServiceProvider.GetService(typeof(DTE));
CreateEventHandlers(visualStudioInstance);
}
and here is the SaveAllCommandCallback:
private void SaveAllCommandCallback(object caller, EventArgs args)
{
SaveAllDocuments();
OutputCommandString("In SaveAll Command Callback");
}
SaveAllDocuments is the method responsible for saving the files to the database. I don't think it is necessary to post that.
My attempt to intercept the standard Visual Studio "Save All" button's command is as follows:
In the Initialize method above, there is a method CreateEventHandlers:
private void CreateEventHandlers(DTE2 visualStudioInstance)
{
Events2 evs = visualStudioInstance.Events as Events2;
Commands cmds = visualStudioInstance.Commands;
Command cmdobj = cmds.Item("File.SaveAll", 0);
saveAllCommandEvents = evs.get_CommandEvents(cmdobj.Guid, cmdobj.ID);
saveAllCommandEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(m_SaveAllCommand_BeforeExecute);
}
And then here is m_SaveAllCommand_BeforeExecute:
private void m_SaveAllCommand_BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
{
SaveAllDocuments();
CancelDefault = true;
}
As you can see, it calls SaveAllDocuments and sets CancelDefault to true, which I think signals to the caller that it has interfered with the command and not only been a listener. Should it be set to true?
Anyways, my main question is, how do I link saveAllCommandEvents.BeforeExecute to the SaveAllCommandCallback? I think it would be better to have SaveAllDocuments called from only one place, in SaveAllCommandCallback, but I don't know how to link the callback to the event of the standard Visual Studio "Save All" button.
I guess this should be simple if one is familiar with events and delegates, but I'm not. I just have a feeling that what I'm currently doing could be improved.
I recommend not to use CancelDefault = true; in m_SaveAllCommand_BeforeExecute and just call SaveTheFilesBackToTheDatabase() from it.

Sharepoint 2010 Programmatically Update List Item in Event Handler

Background
We have a custom developed installed .WSP on a SharePoint 2007 environment and have been in the process of upgrading to 2010. With the upgrade the custom event trigger no longer worked so trying to update and make it work in 2010. But I am running into one issue. Original developers no longer here and I've been the lucky one to have to figure this one out without much of a background with SP Dev.
Goal
When a new list item is created trigger event. Within event, create a shared folder using Item Name and return url, create a wiki-page using item name and include shared document link and return url to wiki page. Part three is update newly created list item with the New Folder url and Wiki Page URL.
Issue
I've gotten the first two parts working but so far have been unable to update the newly created list item with the new Links. I'm able to get the links. I've tried all the basic stuff for updating the list that I have been able to find online with no luck. Nothing to complicated(or so I think). But code is included below. VS is not installed on the server so unable to run debug mode, I don't have direct access to the server. When you create the item there are no client/user side error. Haven't been able to find a log file that has any, that is if it collects errors if the script were to fail out.
Initiation of the Event
public class CreateWikiAndFolder : Microsoft.SharePoint.SPItemEventReceiver
{
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
//this.DisableEventFiring();
base.EventFiringEnabled = false;
string sUrlOfWikiPage = string.Empty;
string sUrlOfNewFolder = string.Empty;
string sSubsiteRUL = string.Empty;
string sCurrentItemTitle = properties.ListItem["Title"].ToString();
string sWikiListName = "TR Wikis";
string sDocLibName = "Shared Documents";
string sTRListID = "TR Status";
if (sTRListID.ToUpper().Equals(properties.ListTitle.ToString().ToUpper()))
{
//Create the Folder
sUrlOfNewFolder = CreateFolder(properties.ListItem.Web, sDocLibName, sCurrentItemTitle);
//Create the Wiki
string ItemDispFormUrl = String.Concat(properties.ListItem.Web.Url, "/", properties.ListItem.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url, "?ID=", properties.ListItem.ID.ToString());
sUrlOfWikiPage = CreateWiki(properties.ListItem.Web, sWikiListName, sCurrentItemTitle, ItemDispFormUrl, sUrlOfNewFolder);
//Update the current TR Item
//Have tried. properties.ListItem["WikiURL"] = sUrlOfWikiPage + ", " + "Wiki";
SPListItem myListItem = properties.ListItem;
SPFieldUrlValue shareFolderURLValue = new SPFieldUrlValue();
shareFolderURLValue.Description = "Shared Folder";
shareFolderURLValue.Url = sUrlOfNewFolder ;
myListItem["SharedFolder"] = shareFolderURLValue;
//I've tried each one separate and together to no luck
myListItem.UpdateOverwriteVersion();
myListItem.Update();
//properties.ListItem.UpdateOverwriteVersion();
}
base.EventFiringEnabled = true;
}
}
}
Note that this is the last thing needed to be figured out for our upgrade.
Got it working. I did both of these at the same time so I'm not sure if it was the combination of both or only one of the items. But one I removed the myListItem.UpdateOverwriteVersion(); line and surrounded the item updated with web.AllowUnsafeUpdates being set to true before and then back to false afterwards.
Also as a note to others, you need to save the properties.ListItem to its own SPListItem which you then update versus trying to manipulate the values at the properties.ListItem["Attribute"], and then update the properties.ListItem.Update. SharePoint doesn't allow the latter option so you have to save to an independent SPListItem, and then modify and update that one. This might not be the best SharePoint lingo, but that is what needs to be done.

Check if the current document in Visual Studio 2012 is a Code Window

I am looking for a way to have my extension check if the currently opened window in visual studio 2012 is one, where the user can write code (or any kind of text, really).
To check if the currently opened window has changed, I use
_DTE.Events.WindowEvents.WindowActivated.
This gives me the EnvDTE.Window that received the focus.
When I look at the properties of that window while debugging, and I look at EnvDTE.Window.Document.Type and it's value is "Text".
However, if I stop debugging and try to access the Document.Type property, it does not exist.
If I look for this property in the documentation of EnvDTE.Window.Document, its description says
Infrastructure. Microsoft Internal Use Only.
So now I am looking for any advice on how I could check if the currently active window is one, where I can write code (or anything else), or some other kind of document (like the solution properties for example).
Edit:
I also tried checking Window.Type and Window.Kind of the active window, but they just tell me that it's a document, not making any differentiation between a resource file, an image file or an actual source file, which is what I'm trying to find out.
Edit²:
The reason why I want to check if the current document is one where I can write code in, is because I want my extension to store information about some of those documents and I want to modify the right-click context menu based on the information I have stored, if any.
It is not a "real" answer, but you can follow status of VS GoTo command - it is available only for text editors:
bool isCodeWindow = IsCommandAvailable("Edit.GoTo");
private bool IsCommandAvailable(string commandName)
{
EnvDTE80.Commands2 commands = dte.Commands as EnvDTE80.Commands2;
if (commands == null)
return false;
EnvDTE.Command command = commands.Item(commandName, 0);
if (command == null)
return false;
return command.IsAvailable;
}
You can check to see if the document is a 'TextDocument'
bool isCodeWindow = dte.CurrentDocument.Object() is EnvDTE.TextDocument;

Highlighting code window text from Visual studio tool window using VSPackage

I'm kind off new to the Visual Studio Extensions. Is there a way to interact to code window from Visual Studio 2010 tool window.
I have a Datagrid hosted on the VisualStudio tool window. DataGrid contains ClassName, MethodName e.tc. On the click of className/MethodName need to acheive the following
Open the particular .cs file containing className/MethodName
HighLight the particular className/MethodName.
I know this acheivable using "IWpfTextView" class, but not sure how. Did a lot of googling but in vain.Even the link below remains to be un-answered link.
Any help on the above will be greatly appreciated.
I actually did almost the same thing. You can see complete source code on Visual Localizer.
Basically you need to do two things:
Obtain IVsTextView instance for the file
call its SetSelection() method which takes range (start line, end line, start column, end column) as parameters. You may also want to call the EnsureSpanVisible() to scroll down.
Obtaining IVsTextView is quite easy as well. In my project (Visual Localizer) there's a class called DocumentViewsManager, located in VLlib/components that has fairly straightforward method called GetTextViewForFile(), which takes only file path as an argument. It does the following:
use VsShellUtilities.IsDocumentOpen method to obtain IVsWindowFrame for given file path
pass this to the VsShellUtilities.GetTextView method, which returns IVsTextView
Hope it helps.
Thanks cre8or.
I found an alternative to do the same.
You need to use "TextSelection" class to highlight the above code line.
foreach (CodeElement codeElement in projectItem.FileCodeModel.CodeElements)// search for the function to be opened
{
// get the namespace elements
if (codeElement.Kind == vsCMElement.vsCMElementNamespace)
{
foreach (CodeElement namespaceElement in codeElement.Children)
{
// get the class elements
if (namespaceElement.Kind == vsCMElement.vsCMElementClass || namespaceElement.Kind == vsCMElement.vsCMElementInterface)
{
foreach (CodeElement classElement in namespaceElement.Children)
{
try
{
// get the function elements to highlight methods in code window
if (classElement.Kind == vsCMElement.vsCMElementFunction)
{
if (!string.IsNullOrEmpty(highlightString))
{
if (classElement.Name.Equals(highlightString, StringComparison.Ordinal))
{
classElement.StartPoint.TryToShow(vsPaneShowHow.vsPaneShowTop, null);
classElement.StartPoint.TryToShow(vsPaneShowHow.vsPaneShowTop, null);
// get the text of the document
EnvDTE.TextSelection textSelection = window.Document.Selection as EnvDTE.TextSelection;
// now set the cursor to the beginning of the function
textSelection.MoveToPoint(classElement.StartPoint);
textSelection.SelectLine();
}
}
}
}
catch
{
}
}
}
}
}
}

Vista TaskDialog Wrapper: Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'

I'm try to use Vista TaskDialog Wrapper and Emulator and I'm getting the following exception:
"Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'."
...in a simple Console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
PSTaskDialog.cTaskDialog.MessageBox(
"MessageBox Title",
"The main instruction text for the message box is shown here.",
"The content text for the message box is shown here and the text willautomatically wrap as needed.",
PSTaskDialog.eTaskDialogButtons.YesNo,
PSTaskDialog.eSysIcons.Information
);
}
}
What am I doing wrong?
UPDATE:
Actually, I'm working on an Excel plugin using excel-dna. How can I control what dll Excel loads?
http://exceldna.codeplex.com/discussions/286990#post728888
I haven't been at Office programming in a while, but my guess is that Excel loads both versions of comctl32, so you may need to use the Activation Context API to direct your code to the version that includes TaskDialog. Some ideas for fixing the problem (not solutions as such):
For test purposes, make a temporary enumeration of all modules in the active process - just to check if 6.10 is actually loaded (see below for a simple example of such an enumeration, albeit with a different intent).
Use the Activation Context API to get to the right version. Example of use from C# (for enabling themes by way of comctl32 6.0) here.
Alternatively (I never actually got this to work reliably in a WPF application I worked on), make a dialog abstraction class, which falls back to MessageDlg depending on the version available to you. There may be better ways of doing the check, but...:
FileVersionInfo version = ProcessUtils.GetLoadedModuleVersion("comctl32.dll");
if (version != null && version.FileMajorPart >= 6 && version.FileMinorPart >= 1)
{
// We can use TaskDialog...
}
else
{
// Use old style MessageBox
}
The enumeration of modules:
internal static FileVersionInfo GetLoadedModuleVersion(string name)
{
Process process = Process.GetCurrentProcess();
foreach (ProcessModule module in process.Modules)
{
if (module.ModuleName.ToLower() == name)
{
return module.FileVersionInfo;
}
return null;
}
}
In addition to what all the others are saying: This error will disappear if you set the ForceEmulationMode on PSTaskDialog to true.

Categories

Resources