Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ParadoxPackage.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.ComponentModel.Design;
6 using System.Diagnostics;
7 using System.Globalization;
8 using System.IO;
9 using System.Linq;
10 using System.Runtime.CompilerServices;
11 using System.Runtime.InteropServices;
12 using System.ServiceModel;
13 using System.Text;
14 using EnvDTE;
15 using EnvDTE80;
16 using Microsoft.Build.Evaluation;
17 using Microsoft.VisualStudio;
18 using Microsoft.VisualStudio.CommandBars;
19 using Microsoft.VisualStudio.Shell;
20 using Microsoft.VisualStudio.Shell.Interop;
21 using NShader;
22 using SiliconStudio.Paradox.VisualStudio.BuildEngine;
24 using SiliconStudio.Paradox.VisualStudio.Shaders;
25 
26 namespace SiliconStudio.Paradox.VisualStudio
27 {
28  /// <summary>
29  /// Quick and temporary VS package to allow platform switch for Paradox.
30  /// This code needs to be largely refactored and correctly designed.
31  /// - alex
32  ///
33  /// This is the class that implements the package exposed by this assembly.
34  /// The minimum requirement for a class to be considered a valid package for Visual Studio
35  /// is to implement the IVsPackage interface and register itself with the shell.
36  /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
37  /// to do it: it derives from the Package class that provides the implementation of the
38  /// IVsPackage interface and uses the registration attributes defined in the framework to
39  /// register itself and its components with the shell.
40  /// </summary>
41  // This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
42  // a package.
43  [PackageRegistration(UseManagedResourcesOnly = true)]
44  // This attribute is used to register the information needed to show this package
45  // in the Help/About dialog of Visual Studio.
46  [InstalledProductRegistration("#110", "#112", Version, IconResourceID = 400)]
47  // This attribute is needed to let the shell know that this package exposes some menus.
48  //[ProvideMenuResource("Menus.ctmenu", 1)]
49  // This attribute registers a tool window exposed by this package.
50  //[ProvideToolWindow(typeof (MyToolWindow))]
51  [Guid(GuidList.guidParadox_VisualStudio_PackagePkgString)]
52  // Paradox Shader LanguageService
53  [ProvideService(typeof(NShaderLanguageService), ServiceName = "Paradox Shader Language Service")]
54  [ProvideLanguageServiceAttribute(typeof(NShaderLanguageService),
55  "Paradox Shader Language",
56  0,
57  EnableCommenting = true,
58  EnableFormatSelection = true,
59  EnableLineNumbers = true,
60  DefaultToInsertSpaces = true
61  )]
62  [ProvideLanguageExtensionAttribute(typeof(NShaderLanguageService), NShaderSupportedExtensions.Paradox_Shader)]
63  [ProvideLanguageExtensionAttribute(typeof(NShaderLanguageService), NShaderSupportedExtensions.Paradox_Effect)]
64  // Paradox C# Shader Key Generator
65  [CodeGeneratorRegistration(typeof(ShaderKeyFileGenerator), ShaderKeyFileGenerator.InternalName, GuidList.vsContextGuidVCSProject, GeneratorRegKeyName = ".pdxsl")]
66  [CodeGeneratorRegistration(typeof(ShaderKeyFileGenerator), ShaderKeyFileGenerator.InternalName, GuidList.vsContextGuidVCSProject, GeneratorRegKeyName = ".pdxfx")]
67  [CodeGeneratorRegistration(typeof(ShaderKeyFileGenerator), ShaderKeyFileGenerator.DisplayName, GuidList.vsContextGuidVCSProject, GeneratorRegKeyName = ShaderKeyFileGenerator.InternalName, GeneratesDesignTimeSource = true, GeneratesSharedDesignTimeSource = true)]
68  // Data C# Code generator
69  [CodeGeneratorRegistration(typeof(DataCodeGenerator), DataCodeGenerator.InternalName, GuidList.vsContextGuidVCSProject, GeneratorRegKeyName = ".pdxdata")]
70  [CodeGeneratorRegistration(typeof(DataCodeGenerator), DataCodeGenerator.DisplayName, GuidList.vsContextGuidVCSProject, GeneratorRegKeyName = DataCodeGenerator.InternalName, GeneratesDesignTimeSource = true, GeneratesSharedDesignTimeSource = true)]
71  // Temporarily force load for easier debugging
72  [ProvideMenuResource("Menus.ctmenu", 1)]
73  [ProvideAutoLoad(VSConstants.UICONTEXT.SolutionExists_string)]
74  public sealed class ParadoxPackage : Package
75  {
76  public const string Version = "1.145";
77 
78  private DTE2 dte2;
79  private AppDomain buildMonitorDomain;
80  private BuildLogPipeGenerator buildLogPipeGenerator;
81  private SolutionEventsListener solutionEventsListener;
82 
83  /// <summary>
84  /// Default constructor of the package.
85  /// Inside this method you can place any initialization code that does not require
86  /// any Visual Studio service because at this point the package object is created but
87  /// not sited yet inside Visual Studio environment. The place to do all the other
88  /// initialization is the Initialize method.
89  /// </summary>
90  public ParadoxPackage()
91  {
92  Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", ToString()));
93  }
94 
95  /// <summary>
96  /// This function is called when the user clicks the menu item that shows the
97  /// tool window. See the Initialize method to see how the menu item is associated to
98  /// this function using the OleMenuCommandService service and the MenuCommand class.
99  /// </summary>
100  private void ShowToolWindow(object sender, EventArgs e)
101  {
102  // Get the instance number 0 of this tool window. This window is single instance so this instance
103  // is actually the only one.
104  // The last flag is set to true so that if the tool window does not exists it will be created.
105  //ToolWindowPane window = FindToolWindow(typeof (MyToolWindow), 0, true);
106  //if ((null == window) || (null == window.Frame))
107  //{
108  // throw new NotSupportedException(Resources.CanNotCreateWindow);
109  //}
110  //var windowFrame = (IVsWindowFrame) window.Frame;
111  //ErrorHandler.ThrowOnFailure(windowFrame.Show());
112  }
113 
114  private void MenuItemCallback(object sender, EventArgs e)
115  {
116  Environment.SetEnvironmentVariable("Test1", "Test2");
117  }
118 
119  #region Package Members
120 
121  /// <summary>
122  /// Initialization of the package; this method is called right after the package is sited, so this is the place
123  /// where you can put all the initialization code that rely on services provided by VisualStudio.
124  /// </summary>
125  protected override void Initialize()
126  {
127  Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", ToString()));
128  base.Initialize();
129 
130  IDEBuildLogger.UserRegistryRoot = UserRegistryRoot;
131 
132  solutionEventsListener = new SolutionEventsListener(this);
133  solutionEventsListener.AfterSolutionBackgroundLoadComplete += solutionEventsListener_AfterSolutionBackgroundLoadComplete;
134 
135  // Initialize the build monitor, that will display BuildEngine results in the Build Output pane.
136  buildLogPipeGenerator = new BuildLogPipeGenerator(this);
137 
138  dte2 = GetGlobalService(typeof(SDTE)) as DTE2;
139 
140  // Register the C# language service
141  var serviceContainer = this as IServiceContainer;
142  var langService = new NShaderLanguageService();
143  langService.SetSite(this);
144  serviceContainer.AddService(typeof(NShaderLanguageService), langService, true);
145 
146  // Add our command handlers for menu (commands must exist in the .vsct file)
147  var mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
148  if (null != mcs)
149  {
150  ParadoxCommands.ServiceProvider = this;
151  ParadoxCommands.RegisterCommands(mcs);
152  }
153 
154  // Get General Output pane (for error logging)
155  var generalOutputPane = GetGeneralOutputPane();
156 
157  var paradoxSdkDir = ParadoxCommandsProxy.ParadoxSdkDir;
158  if (paradoxSdkDir == null)
159  {
160  generalOutputPane.OutputStringThreadSafe("Could not find Paradox SDK directory.\r\n");
161  generalOutputPane.Activate();
162  }
163 
164  // Start PackageBuildMonitorRemote in a separate app domain
165  buildMonitorDomain = ParadoxCommandsProxy.CreateAppDomain();
166  try
167  {
168  var remoteCommands = ParadoxCommandsProxy.CreateProxy(buildMonitorDomain);
169  remoteCommands.StartRemoteBuildLogServer(new BuildMonitorCallback(dte2), buildLogPipeGenerator.LogPipeUrl);
170  }
171  catch (Exception e)
172  {
173  generalOutputPane.OutputStringThreadSafe(string.Format("Error loading Paradox SDK: {0}\r\n", e));
174  generalOutputPane.Activate();
175 
176  // Unload domain right away
177  AppDomain.Unload(buildMonitorDomain);
178  buildMonitorDomain = null;
179  }
180  }
181 
182  private void solutionEventsListener_AfterSolutionBackgroundLoadComplete()
183  {
184  var solution = (IVsSolution)Microsoft.VisualStudio.Shell.Package.GetGlobalService(typeof(IVsSolution));
185  var updatedProjects = new List<string>();
186 
187  foreach (var dteProject in VsHelper.GetDteProjectsInSolution(solution))
188  {
189  var buildProjects = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(dteProject.FileName);
190  foreach (var buildProject in buildProjects)
191  {
192  var packageVersion = buildProject.GetPropertyValue("SiliconStudioPackageParadoxVersion");
193  var currentPackageVersion = buildProject.GetPropertyValue("SiliconStudioPackageParadoxVersionLast");
194  if (!string.IsNullOrEmpty(packageVersion) && packageVersion != currentPackageVersion)
195  {
196  var buildPropertyStorage = VsHelper.ToHierarchy(dteProject) as IVsBuildPropertyStorage;
197  if (buildPropertyStorage != null)
198  {
199  buildPropertyStorage.SetPropertyValue("SiliconStudioPackageParadoxVersionLast", string.Empty, (uint)_PersistStorageType.PST_USER_FILE, packageVersion);
200 
201  // Only "touch" file if there was a version before (we don't want to trigger this on newly created projects)
202  if (!string.IsNullOrEmpty(currentPackageVersion))
203  updatedProjects.Add(buildProject.FullPath);
204  }
205  }
206  }
207  }
208 
209  if (updatedProjects.Count > 0)
210  {
211  var messageBoxResult = VsShellUtilities.ShowMessageBox(this,
212  "Paradox needs to update IntelliSense cache for some projects.\nThis will resave the .csproj and Visual Studio will offer to reload them.\n\nProceed?",
213  "Paradox IntelliSense cache",
214  OLEMSGICON.OLEMSGICON_QUERY,
215  OLEMSGBUTTON.OLEMSGBUTTON_YESNO,
216  OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
217 
218  if (messageBoxResult == 6) // Yes
219  {
220  // Touch files so that VS reload them
221  foreach (var updatedProject in updatedProjects)
222  {
223  File.SetLastWriteTimeUtc(updatedProject, DateTime.UtcNow);
224  }
225  }
226  }
227  }
228 
229  protected override void Dispose(bool disposing)
230  {
231  // Unload build monitor pipe domain
232  if (buildMonitorDomain != null)
233  AppDomain.Unload(buildMonitorDomain);
234  }
235 
236  private IVsOutputWindowPane GetGeneralOutputPane()
237  {
238  var outputWindow = (IVsOutputWindow)Package.GetGlobalService(typeof(SVsOutputWindow));
239 
240  // Get Output pane
241  IVsOutputWindowPane pane;
242  Guid generalPaneGuid = VSConstants.GUID_OutWindowGeneralPane;
243  outputWindow.CreatePane(ref generalPaneGuid, "General", 1, 0);
244  outputWindow.GetPane(ref generalPaneGuid, out pane);
245  return pane;
246  }
247 
248  #endregion
249  }
250 }
override void Initialize()
Initialization of the package; this method is called right after the package is sited, so this is the place where you can put all the initialization code that rely on services provided by VisualStudio.
Supported extensions. Loaded by NShaderScannerFactory. WARNING, you need also to add those extensions...
ParadoxPackage()
Default constructor of the package. Inside this method you can place any initialization code that doe...
Quick and temporary VS package to allow platform switch for Paradox. This code needs to be largely re...