VSPackage command that creates a new solution - c#

How can I create a command in a VSPackage that creates a new solution with a new project (C# Class Library) in it, containing 1 .cs file?

It is not very straighforward but there is an interesting guide on MSDN that explains how to do it. It is for an Add-in but in a VSPackage you have the same set of Visual Studio DTE objects available (the DTE application).
You can define a method that uses GetProjectTemplate and AddFromTemplate to create two console projects. You can define in the method Initialize of your VSPackage class a OLE menu command (if that is what you are looking for):
protected override void Initialize()
{
//// Create the command for the menu item.
var aCommand = new CommandID(GuidList.GuidCmdSet, (int)PkgCmdIdList.CmdId);
var menuItemEnable = new OleMenuCommand((s, e) => createProjectsFromTemplates(), aCommand);
}
And then define a method associated to the command (createProjectsFromTemplates in this case) that creates a solution with a project:
private DTE2 _mApplicationObject;
public DTE2 ApplicationObject
{
get
{
if (_mApplicationObject != null) return _mApplicationObject;
// Get an instance of the currently running Visual Studio IDE
var dte = (DTE)GetService(typeof(DTE));
_mApplicationObject = dte as DTE2;
return _mApplicationObject;
}
}
public void createProjectsFromTemplates()
{
try
{
// Create a solution with two projects in it, based on project
// templates.
Solution2 soln = (Solution2)ApplicationObject.Solution;
string csTemplatePath;
string csPrjPath = "C:\\UserFiles\\user1\\addins\\MyCSProject";
// Get the project template path for a C# console project.
// Console Application is the template name that appears in
// the right pane. "CSharp" is the Language(vstemplate) as seen
// in the registry.
csTemplatePath = soln.GetProjectTemplate(#"Windows\ClassLibrary\ClassLibrary.vstemplate",
"CSharp");
System.Windows.Forms.MessageBox.Show("C# template path: " +
csTemplatePath);
// Create a new C# console project using the template obtained
// above.
soln.AddFromTemplate(csTemplatePath, csPrjPath, "New CSharp
Console Project", false);
}
catch (System.Exception ex)
{
System.Windows.Forms.MessageBox.Show("ERROR: " + ex.Message);
}
}
For Visual Studio versions after 10.0 the zip for template projects is not available anymore. The .vstemplate must be referenced and it is possible to find all the project templates under the folder:
C:\Program Files (x86)\Microsoft Visual Studio 1x.0\Common7\IDE\ProjectTemplates\
More info on this MSDN link.
The method should create a solution with one C# project based on the c# project template (e.g. containing class1.cs as initial file).
You can define your own template as well if you wish and create a solution based on that custom template. Here is a guide from MSDN on how to create custom templates.
hope it helps.

Related

Type-safe way to get embedded resource content in .NET Core 3

I'm using .NET Core 3 preview 6 and Visual Studio 2019 16.2 for creating WinForms application.
In .NET Framework I used type-safe mechanism to load resources, something like that:
this.pictureBox1.BackgroundImage = global::MyNamespace.Properties.Resources.Image1;
this.textBox1.Text = global::MyNamespace.Properties.Resources.Script1;
But in .NET Core 3 I must write special helper class with several methods:
public static class EmbeddedResource
{
public static Image GetImage(String resourceName)
{
try
{
using (var stream = typeof(EmbeddedResource).GetTypeInfo().Assembly.GetManifestResourceStream(resourceName))
return Image.FromStream(stream);
}
catch(Exception exception)
{
throw new Exception($"Failed to read Embedded Resource {resourceName}");
}
}
public static String GetString(String resourceName)
{
try
{
using (var stream = typeof(EmbeddedResource).GetTypeInfo().Assembly.GetManifestResourceStream(resourceName))
using (var reader = new StreamReader(stream, Encoding.UTF8))
return reader.ReadToEnd();
}
catch(Exception exception)
{
throw new Exception($"Failed to read Embedded Resource {resourceName}");
}
}
}
And use it like that:
this.pictureBox1.BackgroundImage = EmbeddedResource.GetImage("MyNamespace.Image1.jpg");
this.textBox1.Text = EmbeddedResource.GetString("MyNamespace.Script1.sql");
Is there a better way (e. g. strictly-typed and resourceName error-safe) to do that?
Thank you in advance.
Visual Studio 2019 16.2 Has design-time support for Resx file for Windows Forms .NET Core Projects. It is the same feature that is supported in previous versions of Visual Studio for Windows Forms classic .NET projects.
It means you can:
Add New Item → Choose Resources File and set a name like Resources.Resx and press Add. The file will be opened in design mode. (Later to open it in design mode, just double click on it.)
Add an image to the designer by dragging an image file and dropping it into the designer. You can also add the image by click on Add Resource tool strip drop down button and choosing Add Existing File ....
Then the image will be accessible using a property which has the same name as the image. For example I created a Properties folder and created Resources.Resx under that folder, then added MyImage.jpg to the resource file, the I could use it this way:
this.BackgroundImage = Properties.Resources.MyImage;
Note - Create default Resource file for the project in Properties folder
Right click on Project → Choose Properties
In project properties window, choose Resources (left side, bottom of the list).
At the center, you will see a link This project does not contain a default resources file. Click here to create one. Click on the link and it will create a Resources.Resx file under Properties folder for your project.

ToastActivatorCLSID missing from AppUserModel

im an currently following this guide to add windows toast notifications to my app.
https://learn.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/send-local-toast-desktop
i need to create a shortcut that contains the System.AppUserModel.ID and System.AppUserModel.ToastActivatorCLSID.
now the website says to just have your installer create this and they recommend using WIX. which is fine but i would rather just create the shortcut from C# code.
so there is this example that creates the shortcut via C#.
https://code.msdn.microsoft.com/windowsdesktop/sending-toast-notifications-71e230a2
but it only shows adding the AppUserModel.ID and not the ToastActivatorCLSID...
here is some of that code...
private void InstallShortcut(String shortcutPath)
{
// Find the path to the current executable
String exePath = Process.GetCurrentProcess().MainModule.FileName;
IShellLinkW newShortcut = (IShellLinkW)new CShellLink();
// Create a shortcut to the exe
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetPath(exePath));
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetArguments(""));
// Open the shortcut property store, set the AppUserModelId property
IPropertyStore newShortcutProperties = (IPropertyStore)newShortcut;
using (PropVariant appId = new PropVariant(APP_ID))
{
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.SetValue(System Properties.System.AppUserModel.ID, appId));
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.Commit());
}
// Commit the shortcut to disk
IPersistFile newShortcutSave = (IPersistFile)newShortcut;
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutSave.Save(shortcutPath, true));
}
the thing is that the AppUserModel does not have a ToastActivatorCLSID property. seems strange.
i figured i could just add another using block to add the ToastActivatorCLSID property like this
using (PropVariant clsId = new PropVariant(CLSID))
{
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.SetValue(System Properties.System.AppUserModel.ToastActivatorCLSID, CLSID));
ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.Commit());
}
but the SystemProperties.System.AppUserModel.ToastActivatorCLSID doesnt exist.
right now the appuser model is coming from Microsoft.WindowsAPICodePack.Shell.PropertySystem.
this page shows it should exist
https://learn.microsoft.com/en-us/windows/desktop/properties/props-system-appusermodel-toastactivatorclsid
i would if with that information i could make some kind of interface or something to add in that ToastActivatorCLSID.
there is very little on the internet on this topic. Don't know if there is a different reference or something.
any help would be great
I've been running into the same problem and I've found a work around.
Clone this github repo: https://github.com/aybe/Windows-API-Code-Pack-1.1
open the WindowsAPICodePack12.sln in visual studio.
open Shell > PropertySystem > SystemProperties.cs
find the AppUserModel class on line 2302
add this code to the class:
public static PropertyKey ToastActivatorCLSID
{
get
{
PropertyKey key = new PropertyKey(new Guid("{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}"), 26);
return key;
}
}
Build the project. Open the bin folder (where the built projects go) and find Microsoft.WindowsAPICodePack.dll and Microsoft.WindowsAPICodePack.Shell.dll
Reference these dlls in your project instead of the original code pack.

Add ClassLibrary Project programmatically

I have a VS 2017 extension and have tried using my own custom Project Template, by adding it programmatically, but things aren't going so well.
In my endeavour to find the mistake, I would like to see whether it is my custom Project Template causing the problem or not. Therefore I want to programmatically add any other existing built-in VS project such as a ClassLibrary type project template.
It seems to be located here:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\ProjectTemplates\CSharp\Windows\1033\
But there isn't a zip folder and I can't create one in that directory according to Windows.
I will be using something similar to the following code:
Solution2 soln = (Solution2)visualStudioInstance.Solution;
string templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, projPath, "MyProjectName", false);
Am I on the right track?
I've tried it and I got an exception, but perhaps it was just because the zip folder doesn't exist.
UPDATE
The exception I get is:
"Object reference not set to an instance of an object."
I get it in the last line of the following code, when I try to add a reference to calcEngineProject. calcEngineProject is null even though it enters the if-statement and should be assigned the value of projCS.Object as VSProject2.
The code is as follows:
templatePath = soln.GetProjectTemplate("ClassLibrary.zip", "CSharp");
soln.AddFromTemplate(templatePath, prjPath, "ClassLibrary1", false);
foreach (Project p in soln.Projects)
{
if (String.Compare(p.Name, "ClassLibrary1") == 0)
{
projCS = p;
break;
}
}
if (projCS != null)
{
calcEngineProject = projCS.Object as VSProject2;
}
calcEngineProject.References.Add(Path.Combine(Config.Engine.EngineBinPath, "Engines.Calculation.dll"));
Also, I saw that templatePath is this:
"C:\PROGRAM FILES (X86)\MICROSOFT VISUAL
STUDIO\2017\PROFESSIONAL\COMMON7\IDE\EXTENSIONS\EYXTAMKA.FB4\ProjectTemplates\CSharp\.NET
Standard\1033\ClassLibrary\ClassLibrary.vstemplate"
and not
\%USERPROFILE%\Documents\My Exported Templates\
as mentioned in Upgrading custom project template

Visual Studio Wizard - Won't add project items to the correct folder

I'm trying to create a custom Visual Studio wizard to create generated code.
Everything works well but the only problem is that the project file won't be saved in right folder. I'm right clicking on a project folder and selecting 'New Item...' but the wizard saves the file in project root.
The code:
public class ProcedureClass : IDTWizard
{
public void Execute(object Application, int hwndOwner, ref object[] ContextParams, ref object[] CustomParams, ref EnvDTE.wizardResult retval)
{
// Showing wizard dialog and generating code here...
var projectItems = ContextParams[2] as ProjectItems;
var project = projectItems.ContainingProject;
retval = wizardResult.wizardResultSuccess;
project.ProjectItems.AddFromTemplate(tempFile, ContextParams[4]);
}
}
Here is an image showing where I clicked and where the file has been created:
This is expected given that your code uses projectItems.ContainingProject, which always returns the root project.
See my article
HOWTO: Navigate the files of a solution from a Visual Studio .NET macro or add-in
http://www.mztools.com/articles/2006/MZ2006004.aspx
The correct code would be:
Get projectItems.Parent, which is an object, which in turn can be an EnvDTE.Project or an EnvDTE.ProjectItem.
If it is an EnvDTE.Project, use Project.ProjectItems.AddFromTemplate(..)
If it is an EnvDTE.ProjectItem, use ProjectItem.ProjectItems.AddFromTemplate(...)

How to Add an Existing Item to a Project Programmatically?

How can I programmatically add an item to a project?
Something similar to
public void AddExistingItem(string projectPath, string existingItemPath)
{
//I'm making up the Project class here as an example
Project p = new Project(projectPath);
p.AddExistingItem(existingItemPath);
}
I want to mimic Visual Studio's Add Existing Item functionality.
VisualStudio project is just a XML file so you can open it using XDocument or XmlDocument and edit.
Add a reference to EnvDTE.dll, and then use ProjectItems.AddFromFile method
As you can read on this page, you must set the Embed Interop Types property of the assembly to false if you add a reference to EnvDTE.dll
Try something like this:
public void createProjectItem(DTE2 dte)
{
//Adds a new Class to an existing Visual Basic project.
Solution2 soln;
Project prj;
soln = (Solution2)_applicationObject.Solution;
ProjectItem prjItem;
String itemPath;
// Point to the first project (the Visual Basic project).
prj = soln.Projects.Item(1);
// Retrieve the path to the class template.
itemPath = soln.GetProjectItemTemplate("Class.zip", "vbproj");
//Create a new project item based on the template, in this
// case, a Class.
prjItem = prj.ProjectItems.AddFromTemplate(itemPath, "MyNewClass");
}
from: http://msdn.microsoft.com/en-us/library/vstudio/ms228774.aspx

Categories