Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: obsolete/Microsoft.VisualStudio.Project/SingleFileGenerator.cs

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 Microsoft.VisualStudio;
9 using Microsoft.VisualStudio.OLE.Interop;
10 using Microsoft.VisualStudio.Shell.Interop;
11 using Microsoft.VisualStudio.TextManager.Interop;
12
13 namespace Microsoft.VisualStudio.Project
14 {
15 /// <summary>
16 /// Provides support for single file generator.
17 /// </summary>
18 internal class SingleFileGenerator : ISingleFileGenerator, IVsGeneratorP rogress
19 {
20
21 #region fields
22 private bool gettingCheckoutStatus;
23 private bool runningGenerator;
24 private ProjectNode projectMgr;
25 #endregion
26
27 #region ctors
28 /// <summary>
29 /// Overloadde ctor.
30 /// </summary>
31 /// <param name="ProjectNode">The associated project</param>
32 internal SingleFileGenerator(ProjectNode projectMgr)
33 {
34 this.projectMgr = projectMgr;
35 }
36 #endregion
37
38 #region IVsGeneratorProgress Members
39
40 public virtual int GeneratorError(int warning, uint level, strin g err, uint line, uint col)
41 {
42 return VSConstants.E_NOTIMPL;
43 }
44
45 public virtual int Progress(uint complete, uint total)
46 {
47 return VSConstants.E_NOTIMPL;
48 }
49
50 #endregion
51
52 #region ISingleFileGenerator
53 /// <summary>
54 /// Runs the generator on the current project item.
55 /// </summary>
56 /// <param name="document"></param>
57 /// <returns></returns>
58 public virtual void RunGenerator(string document)
59 {
60 // Go run the generator on that node, but only if the fi le is dirty
61 // in the running document table. Otherwise there is no need to rerun
62 // the generator because if the original document is not dirty then
63 // the generated output should be already up to date.
64 uint itemid = VSConstants.VSITEMID_NIL;
65 IVsHierarchy hier = (IVsHierarchy)this.projectMgr;
66 if(document != null && hier != null && ErrorHandler.Succ eeded(hier.ParseCanonicalName((string)document, out itemid)))
67 {
68 IVsHierarchy rdtHier;
69 IVsPersistDocData perDocData;
70 uint cookie;
71 if(this.VerifyFileDirtyInRdt((string)document, o ut rdtHier, out perDocData, out cookie))
72 {
73 // Run the generator on the indicated do cument
74 FileNode node = (FileNode)this.projectMg r.NodeFromItemId(itemid);
75 this.InvokeGenerator(node);
76 }
77 }
78 }
79 #endregion
80
81 #region virtual methods
82 /// <summary>
83 /// Invokes the specified generator
84 /// </summary>
85 /// <param name="fileNode">The node on which to invoke the gener ator.</param>
86 protected internal virtual void InvokeGenerator(FileNode fileNod e)
87 {
88 if(fileNode == null)
89 {
90 throw new ArgumentNullException("fileNode");
91 }
92
93 SingleFileGeneratorNodeProperties nodeproperties = fileN ode.NodeProperties as SingleFileGeneratorNodeProperties;
94 if(nodeproperties == null)
95 {
96 throw new InvalidOperationException();
97 }
98
99 string customToolProgID = nodeproperties.CustomTool;
100 if(string.IsNullOrEmpty(customToolProgID))
101 {
102 return;
103 }
104
105 string customToolNamespace = nodeproperties.CustomToolNa mespace;
106
107 try
108 {
109 if(!this.runningGenerator)
110 {
111 //Get the buffer contents for the curren t node
112 string moniker = fileNode.GetMkDocument( );
113
114 this.runningGenerator = true;
115
116 //Get the generator
117 IVsSingleFileGenerator generator;
118 int generateDesignTimeSource;
119 int generateSharedDesignTimeSource;
120 int generateTempPE;
121 SingleFileGeneratorFactory factory = new SingleFileGeneratorFactory(this.projectMgr.ProjectGuid, this.projectMgr.Site);
122 ErrorHandler.ThrowOnFailure(factory.Crea teGeneratorInstance(customToolProgID, out generateDesignTimeSource, out generate SharedDesignTimeSource, out generateTempPE, out generator));
123
124 //Check to see if the generator supports siting
125 IObjectWithSite objWithSite = generator as IObjectWithSite;
126 if(objWithSite != null)
127 {
128 objWithSite.SetSite(fileNode.Ole ServiceProvider);
129 }
130
131 //Determine the namespace
132 if(string.IsNullOrEmpty(customToolNamesp ace))
133 {
134 customToolNamespace = this.Compu teNamespace(moniker);
135 }
136
137 //Run the generator
138 IntPtr[] output = new IntPtr[1];
139 output[0] = IntPtr.Zero;
140 uint outPutSize;
141 string extension;
142 ErrorHandler.ThrowOnFailure(generator.De faultExtension(out extension));
143
144 //Find if any dependent node exists
145 string dependentNodeName = Path.GetFileN ameWithoutExtension(fileNode.FileName) + extension;
146 HierarchyNode dependentNode = fileNode.F irstChild;
147 while(dependentNode != null)
148 {
149 if(string.Compare(dependentNode. ItemNode.GetMetadata(ProjectFileConstants.DependentUpon), fileNode.FileName, Str ingComparison.OrdinalIgnoreCase) == 0)
150 {
151 dependentNodeName = ((Fi leNode)dependentNode).FileName;
152 break;
153 }
154
155 dependentNode = dependentNode.Ne xtSibling;
156 }
157
158 //If you found a dependent node.
159 if(dependentNode != null)
160 {
161 //Then check out the node and de pendent node from SCC
162 if(!this.CanEditFile(dependentNo de.GetMkDocument()))
163 {
164 throw Marshal.GetExcepti onForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
165 }
166 }
167 else //It is a new node to be added to t he project
168 {
169 // Check out the project file if necessary.
170 if(!this.projectMgr.QueryEditPro jectFile(false))
171 {
172 throw Marshal.GetExcepti onForHR(VSConstants.OLE_E_PROMPTSAVECANCELLED);
173 }
174 }
175 IVsTextStream stream;
176 string inputFileContents = this.GetBuffe rContents(moniker, out stream);
177
178 ErrorHandler.ThrowOnFailure(generator.Ge nerate(moniker, inputFileContents, customToolNamespace, output, out outPutSize, this));
179 byte[] data = new byte[outPutSize];
180
181 if(output[0] != IntPtr.Zero)
182 {
183 Marshal.Copy(output[0], data, 0, (int)outPutSize);
184 Marshal.FreeCoTaskMem(output[0]) ;
185 }
186
187 //Todo - Create a file and add it to the Project
188 this.UpdateGeneratedCodeFile(fileNode, d ata, (int)outPutSize, dependentNodeName);
189 }
190 }
191 finally
192 {
193 this.runningGenerator = false;
194 }
195 }
196
197 /// <summary>
198 /// Computes the names space based on the folder for the Project Item. It just replaces DirectorySeparatorCharacter
199 /// with "." for the directory in which the file is located.
200 /// </summary>
201 /// <returns>Returns the computed name space</returns>
202 protected virtual string ComputeNamespace(string projectItemPath )
203 {
204 if(String.IsNullOrEmpty(projectItemPath))
205 {
206 throw new ArgumentException(SR.GetString(SR.Para meterCannotBeNullOrEmpty, CultureInfo.CurrentUICulture), "projectItemPath");
207 }
208
209
210 string nspace = "";
211 string filePath = Path.GetDirectoryName(projectItemPath) ;
212 string[] toks = filePath.Split(new char[] { ':', '\\' }) ;
213 foreach(string tok in toks)
214 {
215 if(!String.IsNullOrEmpty(tok))
216 {
217 string temp = tok.Replace(" ", "");
218 nspace += (temp + ".");
219 }
220 }
221 nspace = nspace.Remove(nspace.LastIndexOf(".", StringCom parison.Ordinal), 1);
222 return nspace;
223 }
224
225 /// <summary>
226 /// This is called after the single file generator has been invo ked to create or update the code file.
227 /// </summary>
228 /// <param name="fileNode">The node associated to the generator< /param>
229 /// <param name="data">data to update the file with</param>
230 /// <param name="size">size of the data</param>
231 /// <param name="fileName">Name of the file to update or create< /param>
232 /// <returns>full path of the file</returns>
233 protected virtual string UpdateGeneratedCodeFile(FileNode fileNo de, byte[] data, int size, string fileName)
234 {
235 string filePath = Path.Combine(Path.GetDirectoryName(fil eNode.GetMkDocument()), fileName);
236 IVsRunningDocumentTable rdt = this.projectMgr.GetService (typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
237
238 // Shouldn't this be an InvalidOperationException instea d with some not to annoying errormessage to the user?
239 if(rdt == null)
240 {
241 ErrorHandler.ThrowOnFailure(VSConstants.E_FAIL);
242 }
243
244 IVsHierarchy hier;
245 uint cookie;
246 uint itemid;
247 IntPtr docData = IntPtr.Zero;
248 ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocument((uin t)(_VSRDTFLAGS.RDT_NoLock), filePath, out hier, out itemid, out docData, out coo kie));
249 if(docData != IntPtr.Zero)
250 {
251 Marshal.Release(docData);
252 IVsTextStream srpStream = null;
253 if(srpStream != null)
254 {
255 int oldLen = 0;
256 int hr = srpStream.GetSize(out oldLen);
257 if(ErrorHandler.Succeeded(hr))
258 {
259 IntPtr dest = IntPtr.Zero;
260 try
261 {
262 dest = Marshal.AllocCoTa skMem(data.Length);
263 Marshal.Copy(data, 0, de st, data.Length);
264 ErrorHandler.ThrowOnFail ure(srpStream.ReplaceStream(0, oldLen, dest, size / 2));
265 }
266 finally
267 {
268 if(dest != IntPtr.Zero)
269 {
270 Marshal.Release( dest);
271 }
272 }
273 }
274 }
275 }
276 else
277 {
278 using(FileStream generatedFileStream = File.Open (filePath, FileMode.OpenOrCreate))
279 {
280 generatedFileStream.Write(data, 0, size) ;
281 }
282
283 EnvDTE.ProjectItem projectItem = fileNode.GetAut omationObject() as EnvDTE.ProjectItem;
284 if(projectItem != null && (this.projectMgr.FindC hild(fileNode.FileName) == null))
285 {
286 projectItem.ProjectItems.AddFromFile(fil ePath);
287 }
288 }
289 return filePath;
290 }
291 #endregion
292
293 #region helpers
294 /// <summary>
295 /// Returns the buffer contents for a moniker.
296 /// </summary>
297 /// <returns>Buffer contents</returns>
298 private string GetBufferContents(string fileName, out IVsTextStr eam srpStream)
299 {
300 Guid CLSID_VsTextBuffer = new Guid("{8E7B96A8-E33D-11d0- A6D5-00C04FB67F6A}");
301 string bufferContents = "";
302 srpStream = null;
303
304 IVsRunningDocumentTable rdt = this.projectMgr.GetService (typeof(SVsRunningDocumentTable)) as IVsRunningDocumentTable;
305 if(rdt != null)
306 {
307 IVsHierarchy hier;
308 IVsPersistDocData persistDocData;
309 uint itemid, cookie;
310 bool docInRdt = true;
311 IntPtr docData = IntPtr.Zero;
312 int hr = NativeMethods.E_FAIL;
313 try
314 {
315 //Getting a read lock on the document. M ust be released later.
316 hr = rdt.FindAndLockDocument((uint)_VSRD TFLAGS.RDT_ReadLock, fileName, out hier, out itemid, out docData, out cookie);
317 if(ErrorHandler.Failed(hr) || docData == IntPtr.Zero)
318 {
319 Guid iid = VSConstants.IID_IUnkn own;
320 cookie = 0;
321 docInRdt = false;
322 ILocalRegistry localReg = this.p rojectMgr.GetService(typeof(SLocalRegistry)) as ILocalRegistry;
323 ErrorHandler.ThrowOnFailure(loca lReg.CreateInstance(CLSID_VsTextBuffer, null, ref iid, (uint)CLSCTX.CLSCTX_INPRO C_SERVER, out docData));
324 }
325
326 persistDocData = Marshal.GetObjectForIUn known(docData) as IVsPersistDocData;
327 }
328 finally
329 {
330 if(docData != IntPtr.Zero)
331 {
332 Marshal.Release(docData);
333 }
334 }
335
336 //Try to get the Text lines
337 IVsTextLines srpTextLines = persistDocData as IV sTextLines;
338 if(srpTextLines == null)
339 {
340 // Try getting a text buffer provider fi rst
341 IVsTextBufferProvider srpTextBufferProvi der = persistDocData as IVsTextBufferProvider;
342 if(srpTextBufferProvider != null)
343 {
344 hr = srpTextBufferProvider.GetTe xtBuffer(out srpTextLines);
345 }
346 }
347
348 if(ErrorHandler.Succeeded(hr))
349 {
350 srpStream = srpTextLines as IVsTextStrea m;
351 if(srpStream != null)
352 {
353 // QI for IVsBatchUpdate and cal l FlushPendingUpdates if they support it
354 IVsBatchUpdate srpBatchUpdate = srpStream as IVsBatchUpdate;
355 if(srpBatchUpdate != null)
356 ErrorHandler.ThrowOnFail ure(srpBatchUpdate.FlushPendingUpdates(0));
357
358 int lBufferSize = 0;
359 hr = srpStream.GetSize(out lBuff erSize);
360
361 if(ErrorHandler.Succeeded(hr))
362 {
363 IntPtr dest = IntPtr.Zer o;
364 try
365 {
366 // Note that Get Stream returns Unicode to us so we don't need to do any conversions
367 dest = Marshal.A llocCoTaskMem((lBufferSize + 1) * 2);
368 ErrorHandler.Thr owOnFailure(srpStream.GetStream(0, lBufferSize, dest));
369 //Get the conten ts
370 bufferContents = Marshal.PtrToStringUni(dest);
371 }
372 finally
373 {
374 if(dest != IntPt r.Zero)
375 Marshal. FreeCoTaskMem(dest);
376 }
377 }
378 }
379
380 }
381 // Unlock the document in the RDT if necessary
382 if(docInRdt && rdt != null)
383 {
384 ErrorHandler.ThrowOnFailure(rdt.UnlockDo cument((uint)(_VSRDTFLAGS.RDT_ReadLock | _VSRDTFLAGS.RDT_Unlock_NoSave), cookie) );
385 }
386
387 if(ErrorHandler.Failed(hr))
388 {
389 // If this failed then it's probably not a text file. In that case,
390 // we just read the file as a binary
391 bufferContents = File.ReadAllText(fileNa me);
392 }
393
394
395 }
396 return bufferContents;
397 }
398
399 /// <summary>
400 /// Returns TRUE if open and dirty. Note that documents can be o pen without a
401 /// window frame so be careful. Returns the DocData and doc cook ie if requested
402 /// </summary>
403 /// <param name="document">document path</param>
404 /// <param name="pHier">hierarchy</param>
405 /// <param name="ppDocData">doc data associated with document</p aram>
406 /// <param name="cookie">item cookie</param>
407 /// <returns>True if FIle is dirty</returns>
408 private bool VerifyFileDirtyInRdt(string document, out IVsHierar chy pHier, out IVsPersistDocData ppDocData, out uint cookie)
409 {
410 int ret = 0;
411 pHier = null;
412 ppDocData = null;
413 cookie = 0;
414
415 IVsRunningDocumentTable rdt = this.projectMgr.GetService (typeof(IVsRunningDocumentTable)) as IVsRunningDocumentTable;
416 if(rdt != null)
417 {
418 IntPtr docData;
419 uint dwCookie = 0;
420 IVsHierarchy srpHier;
421 uint itemid = VSConstants.VSITEMID_NIL;
422
423 ErrorHandler.ThrowOnFailure(rdt.FindAndLockDocum ent((uint)_VSRDTFLAGS.RDT_NoLock, document, out srpHier, out itemid, out docData , out dwCookie));
424 IVsPersistHierarchyItem srpIVsPersistHierarchyIt em = srpHier as IVsPersistHierarchyItem;
425 if(srpIVsPersistHierarchyItem != null)
426 {
427 // Found in the RDT. See if it is dirty
428 try
429 {
430 ErrorHandler.ThrowOnFailure(srpI VsPersistHierarchyItem.IsItemDirty(itemid, docData, out ret));
431 cookie = dwCookie;
432 ppDocData = Marshal.GetObjectFor IUnknown(docData) as IVsPersistDocData;
433 }
434 finally
435 {
436 if(docData != IntPtr.Zero)
437 {
438 Marshal.Release(docData) ;
439 }
440
441 pHier = srpHier;
442 }
443 }
444 }
445 return (ret == 1);
446 }
447 #endregion
448
449
450
451
452 #region QueryEditQuerySave helpers
453 /// <summary>
454 /// This function asks to the QueryEditQuerySave service if it i s possible to
455 /// edit the file.
456 /// </summary>
457 private bool CanEditFile(string documentMoniker)
458 {
459 Trace.WriteLine(string.Format(CultureInfo.CurrentCulture , "\t**** CanEditFile called ****"));
460
461 // Check the status of the recursion guard
462 if(this.gettingCheckoutStatus)
463 {
464 return false;
465 }
466
467 try
468 {
469 // Set the recursion guard
470 this.gettingCheckoutStatus = true;
471
472 // Get the QueryEditQuerySave service
473 IVsQueryEditQuerySave2 queryEditQuerySave = (IVs QueryEditQuerySave2)this.projectMgr.GetService(typeof(SVsQueryEditQuerySave));
474
475 // Now call the QueryEdit method to find the edi t status of this file
476 string[] documents = { documentMoniker };
477 uint result;
478 uint outFlags;
479
480 // Note that this function can popup a dialog to ask the user to checkout the file.
481 // When this dialog is visible, it is possible t o receive other request to change
482 // the file and this is the reason for the recur sion guard.
483 int hr = queryEditQuerySave.QueryEditFiles(
484 0, // Flags
485 1, // Number of elements in the array
486 documents, // Files to edit
487 null, // Input flags
488 null, // Input array of VSQEQS _FILE_ATTRIBUTE_DATA
489 out result, // result of the checkou t
490 out outFlags // Additional flags
491 );
492
493 if(ErrorHandler.Succeeded(hr) && (result == (uin t)tagVSQueryEditResult.QER_EditOK))
494 {
495 // In this case (and only in this case) we can return true from this function.
496 return true;
497 }
498 }
499 finally
500 {
501 this.gettingCheckoutStatus = false;
502 }
503
504 return false;
505 }
506 #endregion
507 }
508 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698