OLD | NEW |
| (Empty) |
1 /// Copyright (c) Microsoft Corporation. All rights reserved. | |
2 | |
3 using System; | |
4 using System.Diagnostics; | |
5 using System.Globalization; | |
6 using System.IO; | |
7 using System.Runtime.InteropServices; | |
8 using System.Windows.Forms; | |
9 using Microsoft.VisualStudio; | |
10 using Microsoft.VisualStudio.Shell.Interop; | |
11 using MSBuild = Microsoft.Build.BuildEngine; | |
12 | |
13 namespace Microsoft.VisualStudio.Project | |
14 { | |
15 /// <summary> | |
16 /// Creates projects within the solution | |
17 /// </summary> | |
18 [CLSCompliant(false)] | |
19 public abstract class ProjectFactory : Microsoft.VisualStudio.Shell.Flav
or.FlavoredProjectFactoryBase | |
20 { | |
21 #region constants | |
22 /// <summary> | |
23 /// The registry key holding the value for the dont show again d
ialog box. | |
24 /// </summary> | |
25 internal const string DontShowProjectSecurityWarningAgain = "Don
tShowProjectSecurityWarningAgain"; | |
26 | |
27 /// <summary> | |
28 /// Security warning when opening/creating client project on UNC
share. | |
29 /// </summary> | |
30 private const string ProjectFolderFotSecureHelp = "vs.projectfol
der_not_secure"; | |
31 #endregion | |
32 | |
33 #region fields | |
34 private Microsoft.VisualStudio.Shell.Package package; | |
35 private System.IServiceProvider site; | |
36 | |
37 /// <summary> | |
38 /// The msbuild engine that we are going to use. | |
39 /// </summary> | |
40 private MSBuild.Engine buildEngine; | |
41 | |
42 /// <summary> | |
43 /// The msbuild project for the project file. | |
44 /// </summary> | |
45 private MSBuild.Project buildProject; | |
46 #endregion | |
47 | |
48 #region properties | |
49 protected Microsoft.VisualStudio.Shell.Package Package | |
50 { | |
51 get | |
52 { | |
53 return this.package; | |
54 } | |
55 } | |
56 | |
57 protected System.IServiceProvider Site | |
58 { | |
59 get | |
60 { | |
61 return this.site; | |
62 } | |
63 } | |
64 | |
65 /// <summary> | |
66 /// The msbuild engine that we are going to use. | |
67 /// </summary> | |
68 protected MSBuild.Engine BuildEngine | |
69 { | |
70 get | |
71 { | |
72 return this.buildEngine; | |
73 } | |
74 } | |
75 | |
76 /// <summary> | |
77 /// The msbuild project for the temporary project file. | |
78 /// </summary> | |
79 protected MSBuild.Project BuildProject | |
80 { | |
81 get | |
82 { | |
83 return this.buildProject; | |
84 } | |
85 set | |
86 { | |
87 this.buildProject = value; | |
88 } | |
89 } | |
90 #endregion | |
91 | |
92 #region ctor | |
93 protected ProjectFactory(Microsoft.VisualStudio.Shell.Package pa
ckage) | |
94 { | |
95 this.package = package; | |
96 this.site = package; | |
97 | |
98 // Please be aware that this methods needs that ServiceP
rovider is valid, thus the ordering of calls in the ctor matters. | |
99 this.buildEngine = Utilities.InitializeMsBuildEngine(thi
s.buildEngine, this.site); | |
100 } | |
101 #endregion | |
102 | |
103 #region abstract methods | |
104 protected abstract ProjectNode CreateProject(); | |
105 #endregion | |
106 | |
107 #region overriden methods | |
108 /// <summary> | |
109 /// Rather than directly creating the project, ask VS to initate
the process of | |
110 /// creating an aggregated project in case we are flavored. We w
ill be called | |
111 /// on the IVsAggregatableProjectFactory to do the real project
creation. | |
112 /// </summary> | |
113 /// <param name="fileName">Project file</param> | |
114 /// <param name="location">Path of the project</param> | |
115 /// <param name="name">Project Name</param> | |
116 /// <param name="flags">Creation flags</param> | |
117 /// <param name="projectGuid">Guid of the project</param> | |
118 /// <param name="project">Project that end up being created by t
his method</param> | |
119 /// <param name="canceled">Was the project creation canceled</pa
ram> | |
120 protected override void CreateProject(string fileName, string lo
cation, string name, uint flags, ref Guid projectGuid, out IntPtr project, out i
nt canceled) | |
121 { | |
122 project = IntPtr.Zero; | |
123 canceled = 0; | |
124 | |
125 // Get the list of GUIDs from the project/template | |
126 string guidsList = this.ProjectTypeGuids(fileName); | |
127 string projectDirectory = String.IsNullOrEmpty(location)
? Path.GetDirectoryName(fileName) : location; | |
128 if(!this.IsProjectLocationSecure(projectDirectory)) | |
129 { | |
130 canceled = 1; | |
131 ErrorHandler.ThrowOnFailure(VSConstants.VS_E_WIZ
ARDBACKBUTTONPRESS); | |
132 } | |
133 | |
134 // Launch the aggregate creation process (we should be c
alled back on our IVsAggregatableProjectFactoryCorrected implementation) | |
135 IVsCreateAggregateProject aggregateProjectFactory = (IVs
CreateAggregateProject)this.Site.GetService(typeof(SVsCreateAggregateProject)); | |
136 int hr = aggregateProjectFactory.CreateAggregateProject(
guidsList, fileName, location, name, flags, ref projectGuid, out project); | |
137 if(hr == VSConstants.E_ABORT) | |
138 canceled = 1; | |
139 ErrorHandler.ThrowOnFailure(hr); | |
140 | |
141 // This needs to be done after the aggregation is comple
ted (to avoid creating a non-aggregated CCW) and as a result we have to go throu
gh the interface | |
142 IProjectEventsProvider eventsProvider = (IProjectEventsP
rovider)Marshal.GetTypedObjectForIUnknown(project, typeof(IProjectEventsProvider
)); | |
143 eventsProvider.ProjectEventsProvider = this.GetProjectEv
entsProvider(); | |
144 | |
145 this.buildProject = null; | |
146 } | |
147 | |
148 | |
149 /// <summary> | |
150 /// Instantiate the project class, but do not proceed with the | |
151 /// initialization just yet. | |
152 /// Delegate to CreateProject implemented by the derived class. | |
153 /// </summary> | |
154 protected override object PreCreateForOuter(IntPtr outerProjectI
Unknown) | |
155 { | |
156 Debug.Assert(this.buildProject != null, "The build proje
ct should have been initialized before calling PreCreateForOuter."); | |
157 GlobalPropertyHandler globalPropertyHandler = new Global
PropertyHandler(this.buildProject); | |
158 globalPropertyHandler.InitializeGlobalProperties(); | |
159 | |
160 // Please be very carefull what is initialized here on t
he ProjectNode. Normally this should only instantiate and return a project node. | |
161 // The reason why one should very carefully add state to
the project node here is that at this point the aggregation has not yet been cr
eated and anything that would cause a CCW for the project to be created would ca
use the aggregation to fail | |
162 // Our reasoning is that there is no other place where s
tate on the project node can be set that is known by the Factory and has to exec
ute before the Load method. | |
163 ProjectNode node = this.CreateProject(); | |
164 Debug.Assert(node != null, "The project failed to be cre
ated"); | |
165 node.BuildEngine = this.buildEngine; | |
166 node.BuildProject = this.buildProject; | |
167 node.GlobalPropetyHandler = globalPropertyHandler; | |
168 globalPropertyHandler.RegisterConfigurationChangeListene
r(node, this.site); | |
169 node.Package = this.package as ProjectPackage; | |
170 return node; | |
171 } | |
172 | |
173 /// <summary> | |
174 /// Retrives the list of project guids from the project file. | |
175 /// If you don't want your project to be flavorable, override | |
176 /// to only return your project factory Guid: | |
177 /// return this.GetType().GUID.ToString("B"); | |
178 /// </summary> | |
179 /// <param name="file">Project file to look into to find the Gui
d list</param> | |
180 /// <returns>List of semi-colon separated GUIDs</returns> | |
181 protected override string ProjectTypeGuids(string file) | |
182 { | |
183 // Load the project so we can extract the list of GUIDs | |
184 | |
185 this.buildProject = Utilities.ReinitializeMsBuildProject
(this.buildEngine, file, this.buildProject); | |
186 | |
187 // Retrieve the list of GUIDs, if it is not specify, mak
e it our GUID | |
188 string guids = buildProject.GetEvaluatedProperty(Project
FileConstants.ProjectTypeGuids); | |
189 if(String.IsNullOrEmpty(guids)) | |
190 guids = this.GetType().GUID.ToString("B"); | |
191 | |
192 return guids; | |
193 } | |
194 #endregion | |
195 | |
196 #region helpers | |
197 private IProjectEvents GetProjectEventsProvider() | |
198 { | |
199 ProjectPackage projectPackage = this.package as ProjectP
ackage; | |
200 Debug.Assert(projectPackage != null, "Package not inheri
ted from framework"); | |
201 if(projectPackage != null) | |
202 { | |
203 foreach(SolutionListener listener in projectPack
age.SolutionListeners) | |
204 { | |
205 IProjectEvents projectEvents = listener
as IProjectEvents; | |
206 if(projectEvents != null) | |
207 { | |
208 return projectEvents; | |
209 } | |
210 } | |
211 } | |
212 | |
213 return null; | |
214 } | |
215 | |
216 /// <summary> | |
217 /// Checks if the project location is secure. If it is not then
it will launch a dialog box prompting the user to acknowledge that the project l
ocation is not secure. | |
218 /// </summary> | |
219 /// <param name="location">The location to check</param> | |
220 /// <returns>true if it is secure, false otherwise.</returns> | |
221 private bool IsProjectLocationSecure(string location) | |
222 { | |
223 if(!Utilities.IsProjectLocationSecure(location)) | |
224 { | |
225 if(Utilities.IsShellInCommandLineMode(this.Site)
|| Utilities.IsInAutomationFunction(this.Site)) | |
226 { | |
227 return false; | |
228 } | |
229 | |
230 string errorMessage = String.Format(CultureInfo.
CurrentCulture, SR.GetString(SR.ProjectLocationNotTrusted, CultureInfo.CurrentUI
Culture), Environment.NewLine, Path.GetDirectoryName(location)); | |
231 return (DontShowAgainDialog.LaunchDontShowAgainD
ialog(this.Site, errorMessage, ProjectFolderFotSecureHelp, DontShowAgainDialog.D
efaultButton.OK, DontShowProjectSecurityWarningAgain) == DialogResult.OK); | |
232 } | |
233 | |
234 return true; | |
235 } | |
236 #endregion | |
237 } | |
238 } | |
OLD | NEW |