PageRenderTime 76ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/vsaddin/src/Builder.cs

https://bitbucket.org/cleto/zeroc-ice-package
C# | 3605 lines | 3476 code | 79 blank | 50 comment | 117 complexity | 53895246aad3d943126a122f84da7a35 MD5 | raw file
Possible License(s): BSD-3-Clause-No-Nuclear-License-2014, GPL-2.0, BSD-3-Clause
  1. // **********************************************************************
  2. //
  3. // Copyright (c) 2003-2013 ZeroC, Inc. All rights reserved.
  4. //
  5. // This copy of Ice is licensed to you under the terms described in the
  6. // ICE_LICENSE file included in this distribution.
  7. //
  8. // **********************************************************************
  9. using System;
  10. using System.Text;
  11. using System.IO;
  12. using System.Diagnostics;
  13. using System.Collections.Generic;
  14. using Extensibility;
  15. using EnvDTE;
  16. using EnvDTE80;
  17. using Microsoft.VisualStudio;
  18. using Microsoft.VisualStudio.CommandBars;
  19. using Microsoft.VisualStudio.VCProjectEngine;
  20. using Microsoft.VisualStudio.Shell;
  21. using Microsoft.VisualStudio.Shell.Interop;
  22. using System.Resources;
  23. using System.Reflection;
  24. using VSLangProj;
  25. using System.Globalization;
  26. using Microsoft.VisualStudio.OLE.Interop;
  27. using System.Runtime.InteropServices;
  28. using System.Windows.Forms;
  29. using DependenciesMap = System.Collections.Generic.Dictionary<string,
  30. System.Collections.Generic.Dictionary<string,
  31. System.Collections.Generic.List<string>>>;
  32. namespace Ice.VisualStudio
  33. {
  34. //
  35. // This class is used to asynchronously read the output of a Slice compiler
  36. // process.
  37. //
  38. public class StreamReader
  39. {
  40. public void appendData(object sendingProcess, DataReceivedEventArgs outLine)
  41. {
  42. if(outLine.Data != null)
  43. {
  44. _data += outLine.Data + "\n";
  45. }
  46. }
  47. public string data()
  48. {
  49. return _data;
  50. }
  51. private string _data = "";
  52. }
  53. public class Builder : IDisposable, IVsTrackProjectDocumentsEvents2
  54. {
  55. protected virtual void Dispose(bool disposing)
  56. {
  57. if(disposing)
  58. {
  59. if(_serviceProvider != null)
  60. {
  61. _serviceProvider.Dispose();
  62. }
  63. if(_errorListProvider != null)
  64. {
  65. _errorListProvider.Dispose();
  66. }
  67. }
  68. }
  69. public void Dispose()
  70. {
  71. Dispose(true);
  72. GC.SuppressFinalize(this);
  73. }
  74. public DTE getCurrentDTE()
  75. {
  76. return _applicationObject.DTE;
  77. }
  78. public DTE2 getApplicationObject()
  79. {
  80. return _applicationObject;
  81. }
  82. public void init(DTE2 application, ext_ConnectMode connectMode, AddIn addInInstance)
  83. {
  84. _applicationObject = application;
  85. _addInInstance = addInInstance;
  86. _connectMode = connectMode;
  87. //
  88. // Subscribe to solution events.
  89. //
  90. if(_connectMode != ext_ConnectMode.ext_cm_CommandLine)
  91. {
  92. _solutionEvents = application.Events.SolutionEvents;
  93. _solutionEvents.Opened += new _dispSolutionEvents_OpenedEventHandler(solutionOpened);
  94. _solutionEvents.AfterClosing += new _dispSolutionEvents_AfterClosingEventHandler(afterClosing);
  95. _solutionEvents.ProjectAdded += new _dispSolutionEvents_ProjectAddedEventHandler(projectAdded);
  96. _solutionEvents.ProjectRemoved += new _dispSolutionEvents_ProjectRemovedEventHandler(projectRemoved);
  97. _solutionEvents.ProjectRenamed += new _dispSolutionEvents_ProjectRenamedEventHandler(projectRenamed);
  98. _selectionEvents = application.Events.SelectionEvents;
  99. _selectionEvents.OnChange += new _dispSelectionEvents_OnChangeEventHandler(selectionChange);
  100. }
  101. _buildEvents = _applicationObject.Events.BuildEvents;
  102. _buildEvents.OnBuildBegin += new _dispBuildEvents_OnBuildBeginEventHandler(buildBegin);
  103. _buildEvents.OnBuildDone += new _dispBuildEvents_OnBuildDoneEventHandler(buildDone);
  104. if(_connectMode != ext_ConnectMode.ext_cm_CommandLine)
  105. {
  106. beginTrackDocumentEvents();
  107. //
  108. // Ensure DEVPATH isn't empty, if there is a project in development mode and DEVPATH is
  109. // empty vshosting process will crash.
  110. //
  111. string devPath = Environment.GetEnvironmentVariable("DEVPATH");
  112. if(String.IsNullOrEmpty(devPath))
  113. {
  114. setDotNetDevPath(Util.getIceHome() + "\\bin\\");
  115. }
  116. //
  117. // Subscribe to command events.
  118. //
  119. foreach(Command c in _applicationObject.Commands)
  120. {
  121. if(c.Name.Equals("Project.AddNewItem"))
  122. {
  123. _addNewItemEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  124. _addNewItemEvent.AfterExecute +=
  125. new _dispCommandEvents_AfterExecuteEventHandler(afterAddNewItem);
  126. }
  127. else if(c.Name.Equals("Edit.Remove"))
  128. {
  129. _editRemoveEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  130. _editRemoveEvent.AfterExecute +=
  131. new _dispCommandEvents_AfterExecuteEventHandler(editDeleteEvent);
  132. }
  133. else if(c.Name.Equals("Edit.Delete"))
  134. {
  135. _editDeleteEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  136. _editDeleteEvent.AfterExecute +=
  137. new _dispCommandEvents_AfterExecuteEventHandler(editDeleteEvent);
  138. }
  139. else if(c.Name.Equals("Project.ExcludeFromProject"))
  140. {
  141. _excludeFromProjectEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  142. _excludeFromProjectEvent.BeforeExecute +=
  143. new _dispCommandEvents_BeforeExecuteEventHandler(beforeExcludeFromProjectEvent);
  144. _excludeFromProjectEvent.AfterExecute +=
  145. new _dispCommandEvents_AfterExecuteEventHandler(afterExcludeFromProjectEvent);
  146. }
  147. else if(c.Name.Equals("Project.AddExistingItem"))
  148. {
  149. _addExistingItemEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  150. _addExistingItemEvent.AfterExecute +=
  151. new _dispCommandEvents_AfterExecuteEventHandler(afterAddExistingItem);
  152. }
  153. else if(c.Name.Equals("Build.Cancel"))
  154. {
  155. _buildCancelEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  156. _buildCancelEvent.AfterExecute +=
  157. new _dispCommandEvents_AfterExecuteEventHandler(afterBuildCancel);
  158. }
  159. else if(c.Name.Equals("Debug.Start"))
  160. {
  161. _debugStartEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  162. _debugStartEvent.BeforeExecute +=
  163. new _dispCommandEvents_BeforeExecuteEventHandler(setDebugEnvironmentStartupProject);
  164. }
  165. else if(c.Name.Equals("Debug.StepInto"))
  166. {
  167. _debugStepIntoEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  168. _debugStepIntoEvent.BeforeExecute +=
  169. new _dispCommandEvents_BeforeExecuteEventHandler(setDebugEnvironmentStartupProject);
  170. }
  171. else if(c.Name.Equals("ClassViewContextMenus.ClassViewProject.Debug.StepIntonewinstance"))
  172. {
  173. _debugStepIntoNewInstance = application.Events.get_CommandEvents(c.Guid, c.ID);
  174. _debugStepIntoNewInstance.BeforeExecute +=
  175. new _dispCommandEvents_BeforeExecuteEventHandler(setDebugEnvironmentActiveProject);
  176. }
  177. else if (c.Name.Equals("Debug.StartWithoutDebugging"))
  178. {
  179. _debugStartWithoutDebuggingEvent = application.Events.get_CommandEvents(c.Guid, c.ID);
  180. _debugStartWithoutDebuggingEvent.BeforeExecute +=
  181. new _dispCommandEvents_BeforeExecuteEventHandler(setDebugEnvironmentStartupProject);
  182. }
  183. else if (c.Name.Equals("ClassViewContextMenus.ClassViewProject.Debug.Startnewinstance"))
  184. {
  185. _debugStartNewInstance = application.Events.get_CommandEvents(c.Guid, c.ID);
  186. _debugStartNewInstance.BeforeExecute +=
  187. new _dispCommandEvents_BeforeExecuteEventHandler(setDebugEnvironmentActiveProject);
  188. }
  189. else if (c.Guid.Equals(Util.refreshCommandGUID) && c.ID == Util.refreshCommandID)
  190. {
  191. Util.setRefreshCommand(c);
  192. }
  193. }
  194. }
  195. _serviceProvider =
  196. new ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider)_applicationObject.DTE);
  197. initErrorListProvider();
  198. if(connectMode != ext_ConnectMode.ext_cm_CommandLine)
  199. {
  200. setupCommandBars();
  201. }
  202. }
  203. void selectionChange()
  204. {
  205. try
  206. {
  207. Project p = getActiveProject();
  208. if(p != null && Util.isSliceBuilderEnabled(p))
  209. {
  210. initializeProject(p);
  211. }
  212. }
  213. catch(Exception ex)
  214. {
  215. Util.unexpectedExceptionWarning(ex);
  216. throw;
  217. }
  218. }
  219. void initializeProject(Project p)
  220. {
  221. DependenciesMap dependenciesMap = getDependenciesMap();
  222. if(p != null && !dependenciesMap.ContainsKey(p.FullName))
  223. {
  224. if((Util.isCSharpProject(p) || Util.isCppProject(p)) && Util.isSliceBuilderEnabled(p))
  225. {
  226. Util.fix(p);
  227. Util.getCurrentDTE().StatusBar.Text = "Ice Add-in: checking/updating settings for project '" + p.FullName + "'";
  228. Util.verifyProjectSettings(p);
  229. Util.getCurrentDTE().StatusBar.Text = "Ice Add-in: loading project '" + p.FullName + "'";
  230. if(!Util.isVBProject(p))
  231. {
  232. dependenciesMap[p.FullName] = new Dictionary<string, List<string>>();
  233. buildProject(p, true, vsBuildScope.vsBuildScopeSolution, false);
  234. }
  235. }
  236. }
  237. if(hasErrors())
  238. {
  239. bringErrorsToFront();
  240. }
  241. }
  242. void editDeleteEvent(string Guid, int ID, object CustomIn, object CustomOut)
  243. {
  244. try
  245. {
  246. if(_deletedFile == null)
  247. {
  248. return;
  249. }
  250. Project project = getActiveProject();
  251. if(project == null)
  252. {
  253. return;
  254. }
  255. removeDependency(project, _deletedFile);
  256. _deletedFile = null;
  257. clearErrors(project);
  258. buildProject(project, false, vsBuildScope.vsBuildScopeProject, false);
  259. }
  260. catch(Exception ex)
  261. {
  262. Util.unexpectedExceptionWarning(ex);
  263. throw;
  264. }
  265. }
  266. //
  267. // In C# project type the delete event isn't triggered by exclude item command.
  268. // We use the before and after events of the command to remove generated items
  269. // when a slice file is excluded. C++ projects handle that as part of delete item
  270. // event.
  271. //
  272. void afterExcludeFromProjectEvent(string Guid, int ID, object CustomIn, object CustomOut)
  273. {
  274. try
  275. {
  276. if(String.IsNullOrEmpty(_excludedItem))
  277. {
  278. return;
  279. }
  280. Project p = getActiveProject();
  281. if(!Util.isCSharpProject(p) || !Util.isSliceBuilderEnabled(p))
  282. {
  283. return;
  284. }
  285. ProjectItem item = Util.findItem(_excludedItem, p.ProjectItems);
  286. if(item != null)
  287. {
  288. item.Delete();
  289. }
  290. updateDependencies(p);
  291. }
  292. catch(Exception ex)
  293. {
  294. Util.unexpectedExceptionWarning(ex);
  295. throw;
  296. }
  297. }
  298. //
  299. // In C# project type the delete event isn't triggered by exclude item command.
  300. // We use the before and after events of the command to remove generated items
  301. // when a slice file is excluded. C++ projects handle that as part of delete item
  302. // event.
  303. //
  304. public void beforeExcludeFromProjectEvent(string Guid, int ID, object obj, object CustomOut, ref bool done)
  305. {
  306. try
  307. {
  308. Project p = getActiveProject();
  309. if(!Util.isCSharpProject(p) || !Util.isSliceBuilderEnabled(p))
  310. {
  311. return;
  312. }
  313. ProjectItem item = Util.getSelectedProjectItem(p.DTE);
  314. if(item == null)
  315. {
  316. return;
  317. }
  318. if(!Util.isSliceFilename(item.Name))
  319. {
  320. return;
  321. }
  322. _excludedItem = getCSharpGeneratedFileName(p, item, "cs");
  323. return;
  324. }
  325. catch(Exception ex)
  326. {
  327. Util.write(null, Util.msgLevel.msgError, ex.ToString() + "\n");
  328. Util.unexpectedExceptionWarning(ex);
  329. throw;
  330. }
  331. }
  332. public IVsSolution getIVsSolution()
  333. {
  334. return (IVsSolution) _serviceProvider.GetService(typeof(IVsSolution));
  335. }
  336. public void buildDone(vsBuildScope Scope, vsBuildAction Action)
  337. {
  338. try
  339. {
  340. Util.solutionExplorerRefresh();
  341. _sliceBuild = false;
  342. //
  343. // If a Slice file has changed during the build, we rebuild that project's
  344. // Slice files now that the build is done.
  345. //
  346. List<Project> rebuildProjects = getRebuildProjects();
  347. foreach(Project p in rebuildProjects)
  348. {
  349. buildProject(p, false, vsBuildScope.vsBuildScopeProject, false);
  350. }
  351. rebuildProjects.Clear();
  352. }
  353. catch(Exception ex)
  354. {
  355. Util.unexpectedExceptionWarning(ex);
  356. throw;
  357. }
  358. finally
  359. {
  360. _buildProject = null;
  361. _building = false;
  362. }
  363. }
  364. //
  365. // Return true if the project build is in process.
  366. //
  367. public bool isBuilding(Project project)
  368. {
  369. if(!isBuilding())
  370. {
  371. return false;
  372. }
  373. if(_buildScope == vsBuildScope.vsBuildScopeSolution)
  374. {
  375. return true;
  376. }
  377. if(_buildScope == vsBuildScope.vsBuildScopeProject &&
  378. _buildProject == project)
  379. {
  380. return true;
  381. }
  382. return false;
  383. }
  384. //
  385. // Is our project building?
  386. //
  387. public bool isBuilding()
  388. {
  389. return _building;
  390. }
  391. //
  392. // If a Slice file created with "Add New Item" command cannot be added
  393. // to the project because the generated items will override an existing item,
  394. // the Slice file must be deleted from disk, here, after the command has
  395. // been executed.
  396. //
  397. public void afterAddNewItem(string Guid, int ID, object obj, object CustomOut)
  398. {
  399. try
  400. {
  401. foreach(String path in _deleted)
  402. {
  403. ProjectItem item = Util.findItem(path);
  404. if(item != null)
  405. {
  406. item.Remove();
  407. }
  408. if(String.IsNullOrEmpty(path))
  409. {
  410. continue;
  411. }
  412. if(File.Exists(path))
  413. {
  414. try
  415. {
  416. File.Delete(path);
  417. }
  418. catch(System.SystemException)
  419. {
  420. // Can happen if the file is used by another process.
  421. }
  422. }
  423. }
  424. _deleted.Clear();
  425. }
  426. catch(Exception ex)
  427. {
  428. Util.unexpectedExceptionWarning(ex);
  429. throw;
  430. }
  431. }
  432. //
  433. // If a Slice file added with "Add Existing Item" command cannot be added
  434. // to the project because the generated items will override an existing item,
  435. // the item must not be deleted here, we must empty the _deleted list so the
  436. // file isn't later removed.
  437. //
  438. public void afterAddExistingItem(string Guid, int ID, object obj, object CustomOut)
  439. {
  440. try
  441. {
  442. foreach (String path in _deleted)
  443. {
  444. ProjectItem item = Util.findItem(path);
  445. if(item != null)
  446. {
  447. item.Remove();
  448. }
  449. }
  450. _deleted.Clear();
  451. }
  452. catch(Exception ex)
  453. {
  454. Util.unexpectedExceptionWarning(ex);
  455. throw;
  456. }
  457. }
  458. public void afterBuildCancel(string Guid, int ID, object obj, object CustomOut)
  459. {
  460. try
  461. {
  462. Util.solutionExplorerRefresh();
  463. _sliceBuild = false;
  464. //
  465. // If a Slice file has changed during the build, we rebuild that project's
  466. // Slice files now that the build has been canceled.
  467. //
  468. List<Project> rebuildProjects = getRebuildProjects();
  469. foreach(Project p in rebuildProjects)
  470. {
  471. buildProject(p, false, vsBuildScope.vsBuildScopeProject, false);
  472. }
  473. rebuildProjects.Clear();
  474. }
  475. catch(Exception ex)
  476. {
  477. Util.unexpectedExceptionWarning(ex);
  478. throw;
  479. }
  480. finally
  481. {
  482. _buildProject = null;
  483. _building = false;
  484. }
  485. }
  486. public void setDebugEnvironmentStartupProject(string Guid, int ID, object obj, object CustomOut, ref bool done)
  487. {
  488. setDebugEnvironment(getStartupProject());
  489. }
  490. public void setDebugEnvironmentActiveProject(string Guid, int ID, object obj, object CustomOut, ref bool done)
  491. {
  492. setDebugEnvironment(getActiveProject());
  493. }
  494. public void setDebugEnvironment(Project project)
  495. {
  496. try
  497. {
  498. if(project != null && Util.isSliceBuilderEnabled(project))
  499. {
  500. if(Util.isCppProject(project))
  501. {
  502. VCProject vcProject = (VCProject)project.Object;
  503. IVCCollection configurations = (IVCCollection)vcProject.Configurations;
  504. foreach(VCConfiguration conf in configurations)
  505. {
  506. Util.addIceCppEnvironment((VCDebugSettings)conf.DebugSettings, project);
  507. }
  508. }
  509. else if(Util.isCSharpProject(project) || Util.isVBProject(project))
  510. {
  511. setDotNetDebugEnvironment(project);
  512. }
  513. }
  514. }
  515. catch(Exception ex)
  516. {
  517. Util.unexpectedExceptionWarning(ex);
  518. throw;
  519. }
  520. }
  521. //
  522. // Set DEVPATH if .NET development mode is enabled and project type is C# or VB,
  523. // otherwise do nothing.
  524. //
  525. // NOTE: for Silverlight projects we don't need to set DEVPATH.
  526. //
  527. private void setDotNetDebugEnvironment(Project project)
  528. {
  529. //
  530. // If development mode isn't enabled then don't set DEVPATH.
  531. //
  532. if(!Util.developmentMode(project))
  533. {
  534. return;
  535. }
  536. //
  537. // Check if vshosting process is enabled, if so disable it before updating
  538. // environment variables. If it is running it will be stopped.
  539. //
  540. bool vsHosting = false;
  541. if(Util.useVSHostingProcess(project))
  542. {
  543. Util.setVsHostingProcess(project, false);
  544. vsHosting = true;
  545. }
  546. setDotNetDevPath(Util.getCsBinDir(project));
  547. //
  548. // Re-enable the vshosting process if it was previously enabled,
  549. // so it reads the new environment when it is started by Visual Studio.
  550. //
  551. if(vsHosting)
  552. {
  553. Util.setVsHostingProcess(project, true);
  554. }
  555. }
  556. private static void setDotNetDevPath(string csBinPath)
  557. {
  558. string devPath = Environment.GetEnvironmentVariable("DEVPATH");
  559. if(String.IsNullOrEmpty(devPath))
  560. {
  561. Environment.SetEnvironmentVariable("DEVPATH", csBinPath);
  562. return;
  563. }
  564. if(devPath.Contains(csBinPath))
  565. {
  566. ComponentList list = new ComponentList(csBinPath.Split(Path.PathSeparator));
  567. list.Remove(csBinPath);
  568. devPath = list.ToString(Path.PathSeparator);
  569. }
  570. devPath = csBinPath + Path.PathSeparator + devPath;
  571. devPath = devPath.Trim(Path.PathSeparator);
  572. Environment.SetEnvironmentVariable("DEVPATH", devPath);
  573. }
  574. public void disconnect()
  575. {
  576. if(_iceConfigurationCmd != null)
  577. {
  578. _iceConfigurationCmd.Delete();
  579. }
  580. if(_connectMode != ext_ConnectMode.ext_cm_CommandLine)
  581. {
  582. _solutionEvents.Opened -= new _dispSolutionEvents_OpenedEventHandler(solutionOpened);
  583. _solutionEvents.AfterClosing -= new _dispSolutionEvents_AfterClosingEventHandler(afterClosing);
  584. _solutionEvents.ProjectAdded -= new _dispSolutionEvents_ProjectAddedEventHandler(projectAdded);
  585. _solutionEvents.ProjectRemoved -= new _dispSolutionEvents_ProjectRemovedEventHandler(projectRemoved);
  586. _solutionEvents.ProjectRenamed -= new _dispSolutionEvents_ProjectRenamedEventHandler(projectRenamed);
  587. _solutionEvents = null;
  588. }
  589. _buildEvents.OnBuildBegin -= new _dispBuildEvents_OnBuildBeginEventHandler(buildBegin);
  590. _buildEvents.OnBuildDone -= new _dispBuildEvents_OnBuildDoneEventHandler(buildDone);
  591. _buildEvents = null;
  592. if(_connectMode != ext_ConnectMode.ext_cm_CommandLine)
  593. {
  594. endTrackDocumentEvents();
  595. }
  596. if(_dependenciesMap != null)
  597. {
  598. _dependenciesMap.Clear();
  599. _dependenciesMap = null;
  600. }
  601. if(_rebuildProjects != null)
  602. {
  603. _rebuildProjects.Clear();
  604. _rebuildProjects = null;
  605. }
  606. _errorCount = 0;
  607. if(_errors != null)
  608. {
  609. _errors.Clear();
  610. _errors = null;
  611. }
  612. if(_fileTracker != null)
  613. {
  614. _fileTracker.clear();
  615. _fileTracker = null;
  616. }
  617. }
  618. private void setupCommandBars()
  619. {
  620. _iceConfigurationCmd = null;
  621. try
  622. {
  623. _iceConfigurationCmd =
  624. _applicationObject.Commands.Item(_addInInstance.ProgID + ".IceConfiguration", -1);
  625. }
  626. catch(ArgumentException)
  627. {
  628. object[] contextGUIDS = new object[] { };
  629. _iceConfigurationCmd =
  630. ((Commands2)_applicationObject.Commands).AddNamedCommand2(_addInInstance,
  631. "IceConfiguration",
  632. "Ice Configuration...",
  633. "Ice Configuration...",
  634. true, -1, ref contextGUIDS,
  635. (int)vsCommandStatus.vsCommandStatusSupported +
  636. (int)vsCommandStatus.vsCommandStatusEnabled,
  637. (int)vsCommandStyle.vsCommandStylePictAndText,
  638. vsCommandControlType.vsCommandControlTypeButton);
  639. }
  640. if(_iceConfigurationCmd == null)
  641. {
  642. MessageBox.Show("Error initializing Ice Visual Studio Add-in.\n" +
  643. "Cannot create required commands",
  644. "Ice Visual Studio Add-in",
  645. MessageBoxButtons.OK,
  646. MessageBoxIcon.Error,
  647. MessageBoxDefaultButton.Button1,
  648. (MessageBoxOptions)0);
  649. return;
  650. }
  651. CommandBar toolsCmdBar = ((CommandBars)_applicationObject.CommandBars)["Tools"];
  652. _iceConfigurationCmd.AddControl(toolsCmdBar, toolsCmdBar.Controls.Count + 1);
  653. CommandBar projectCmdBar = projectCommandBar();
  654. _iceConfigurationCmd.AddControl(projectCmdBar, projectCmdBar.Controls.Count + 1);
  655. }
  656. public void afterClosing()
  657. {
  658. try
  659. {
  660. clearErrors();
  661. removeDocumentEvents();
  662. if(_dependenciesMap != null)
  663. {
  664. _dependenciesMap.Clear();
  665. _dependenciesMap = null;
  666. }
  667. if(_rebuildProjects != null)
  668. {
  669. _rebuildProjects.Clear();
  670. _rebuildProjects = null;
  671. }
  672. }
  673. catch(Exception ex)
  674. {
  675. Util.unexpectedExceptionWarning(ex);
  676. throw;
  677. }
  678. finally
  679. {
  680. _opened = false;
  681. }
  682. }
  683. public void solutionOpened()
  684. {
  685. try
  686. {
  687. _opening = true;
  688. DependenciesMap dependenciesMap = getDependenciesMap();
  689. initDocumentEvents();
  690. }
  691. catch(Exception ex)
  692. {
  693. _opening = false;
  694. Util.unexpectedExceptionWarning(ex);
  695. throw;
  696. }
  697. Util.getCurrentDTE().StatusBar.Text = "Ready";
  698. _opening = false;
  699. _opened = false;
  700. }
  701. //
  702. // Enable slice builder for the project with default components.
  703. //
  704. public void addBuilderToProject(Project project)
  705. {
  706. addBuilderToProject(project, new ComponentList());
  707. }
  708. //
  709. // Enable Slice builder for the project, and enable the components that are
  710. // in components. If components list is empty, the default set of components
  711. // are added to the project.
  712. //
  713. // Note: Components in this context is the list of Ice libraries or assemblies
  714. // that will be added to the project.
  715. //
  716. public void addBuilderToProject(Project project, ComponentList components)
  717. {
  718. if(Util.isCppProject(project))
  719. {
  720. Util.addIceCppConfigurations(project);
  721. if(components.Count == 0)
  722. {
  723. components =
  724. new ComponentList(Util.getProjectProperty(project, Util.PropertyIceComponents));
  725. }
  726. if(!components.Contains("Ice"))
  727. {
  728. components.Add("Ice");
  729. }
  730. if(!Util.isWinRTProject(project))
  731. {
  732. if(!components.Contains("IceUtil"))
  733. {
  734. components.Add("IceUtil");
  735. }
  736. }
  737. Util.addIceCppLibs(project, components);
  738. }
  739. else
  740. {
  741. if(Util.isCSharpProject(project))
  742. {
  743. bool development = Util.developmentMode(project);
  744. if(components.Count == 0)
  745. {
  746. components =
  747. new ComponentList(Util.getProjectProperty(project, Util.PropertyIceComponents));
  748. }
  749. if(!components.Contains("Ice"))
  750. {
  751. components.Add("Ice");
  752. }
  753. string iceHome = Util.getIceHome();
  754. foreach(string component in components)
  755. {
  756. Util.addDotNetReference(project, component, development);
  757. }
  758. }
  759. else if(Util.isVBProject(project))
  760. {
  761. string iceHome = Util.getIceHome();
  762. bool development = Util.developmentMode(project);
  763. if(components.Count == 0)
  764. {
  765. components =
  766. new ComponentList(Util.getProjectProperty(project, Util.PropertyIceComponents));
  767. }
  768. if(!components.Contains("Ice"))
  769. {
  770. components.Add("Ice");
  771. }
  772. foreach(string component in components)
  773. {
  774. Util.addDotNetReference(project, component, development);
  775. }
  776. }
  777. }
  778. Util.setProjectProperty(project, Util.PropertyIceComponents, "");
  779. Util.setProjectProperty(project, Util.PropertyIce, true.ToString());
  780. if(hasErrors(project))
  781. {
  782. bringErrorsToFront();
  783. }
  784. }
  785. public void removeBuilderFromProject(Project project, ComponentList components)
  786. {
  787. cleanProject(project, true);
  788. if(Util.isCppProject(project))
  789. {
  790. Util.removeIceCppConfigurations(project);
  791. Util.setProjectProperty(project, Util.PropertyIceComponents, components.ToString());
  792. }
  793. else if(Util.isCSharpProject(project))
  794. {
  795. Util.removeDotNetReference(project, "Ice");
  796. }
  797. Util.setProjectProperty(project, Util.PropertyIceComponents, components.ToString());
  798. Util.setProjectProperty(project, Util.PropertyIce, false.ToString());
  799. }
  800. //
  801. // Ensure that generated items are opened in read only mode.
  802. //
  803. private void documentOpened(Document document)
  804. {
  805. try
  806. {
  807. if(document == null || document.ProjectItem == null || document.ProjectItem.ContainingProject == null)
  808. {
  809. return;
  810. }
  811. if(!Util.isSliceBuilderEnabled(document.ProjectItem.ContainingProject))
  812. {
  813. return;
  814. }
  815. if(fileTracker().hasGeneratedFile(document.ProjectItem.ContainingProject, document.FullName))
  816. {
  817. if(!document.ReadOnly)
  818. {
  819. document.ReadOnly = true;
  820. }
  821. }
  822. }
  823. catch(Exception ex)
  824. {
  825. Util.unexpectedExceptionWarning(ex);
  826. throw;
  827. }
  828. }
  829. public void documentSaved(Document document)
  830. {
  831. try
  832. {
  833. Project project = null;
  834. try
  835. {
  836. project = document.ProjectItem.ContainingProject;
  837. }
  838. catch(Exception)
  839. {
  840. //
  841. // Expected when documents are created during project initialization
  842. // and the ProjectItem is not yet available.
  843. //
  844. return;
  845. }
  846. if(!Util.isSliceBuilderEnabled(project))
  847. {
  848. return;
  849. }
  850. if(!Util.isSliceFilename(document.Name))
  851. {
  852. return;
  853. }
  854. //
  855. // If build is in proccess, we don't run the slice compiler now, we append the document
  856. // to a list of projects that have changes and return. The projects on this list
  857. // will be rebuilt when the current build process is done or canceled, see
  858. // "buildDone" and "afterBuildCancel" methods in this class.
  859. //
  860. if(isBuilding(project))
  861. {
  862. List<Project> rebuildProjects = getRebuildProjects();
  863. if(!rebuildProjects.Contains(project))
  864. {
  865. rebuildProjects.Add(project);
  866. }
  867. return;
  868. }
  869. clearErrors(project);
  870. buildProject(project, false, vsBuildScope.vsBuildScopeProject, false);
  871. Util.solutionExplorerRefresh();
  872. }
  873. catch(Exception ex)
  874. {
  875. Util.unexpectedExceptionWarning(ex);
  876. throw;
  877. }
  878. }
  879. public void projectAdded(Project project)
  880. {
  881. if(!_opened)
  882. {
  883. return;
  884. }
  885. try
  886. {
  887. if(Util.isSliceBuilderEnabled(project))
  888. {
  889. Util.verifyProjectSettings(project);
  890. updateDependencies(project);
  891. Util.solutionExplorerRefresh();
  892. }
  893. }
  894. catch(Exception ex)
  895. {
  896. Util.unexpectedExceptionWarning(ex);
  897. throw;
  898. }
  899. }
  900. public void projectRemoved(Project project)
  901. {
  902. try
  903. {
  904. DependenciesMap dependenciesMap = getDependenciesMap();
  905. if(dependenciesMap.ContainsKey(project.FullName))
  906. {
  907. dependenciesMap.Remove(project.FullName);
  908. }
  909. List<Project> rebuildProjects = getRebuildProjects();
  910. foreach(Project p in rebuildProjects)
  911. {
  912. if(project == p)
  913. {
  914. rebuildProjects.Remove(p);
  915. break;
  916. }
  917. }
  918. }
  919. catch(Exception ex)
  920. {
  921. Util.unexpectedExceptionWarning(ex);
  922. throw;
  923. }
  924. }
  925. public void projectRenamed(Project project, string oldName)
  926. {
  927. try
  928. {
  929. DependenciesMap dependenciesMap = getDependenciesMap();
  930. String oldPath = Path.Combine(Path.GetDirectoryName(project.FullName), oldName);
  931. if(dependenciesMap.ContainsKey(oldPath))
  932. {
  933. dependenciesMap.Remove(oldPath);
  934. }
  935. updateDependencies(project);
  936. }
  937. catch(Exception ex)
  938. {
  939. Util.unexpectedExceptionWarning(ex);
  940. throw;
  941. }
  942. }
  943. public void cleanProject(Project project, bool remove)
  944. {
  945. DTE dte = Util.getCurrentDTE();
  946. if(!_opening)
  947. {
  948. dte.StatusBar.Text = "Ice Add-in: cleaning project '" + project.FullName + "'";
  949. }
  950. if(project == null)
  951. {
  952. return;
  953. }
  954. if(!Util.isSliceBuilderEnabled(project))
  955. {
  956. return;
  957. }
  958. clearErrors(project);
  959. if(Util.isCSharpProject(project))
  960. {
  961. removeCSharpGeneratedItems(project, project.ProjectItems, remove);
  962. }
  963. else if(Util.isCppProject(project))
  964. {
  965. removeCppGeneratedItems(project.ProjectItems, remove);
  966. }
  967. if(!_opening)
  968. {
  969. dte.StatusBar.Text = "Ready";
  970. }
  971. }
  972. public void removeCSharpGeneratedItems(Project project, ProjectItems items, bool remove)
  973. {
  974. if(project == null)
  975. {
  976. return;
  977. }
  978. if(items == null)
  979. {
  980. return;
  981. }
  982. List<ProjectItem> tmpItems = Util.clone(items);
  983. foreach(ProjectItem i in tmpItems)
  984. {
  985. if(i == null)
  986. {
  987. continue;
  988. }
  989. if(Util.isProjectItemFolder(i))
  990. {
  991. removeCSharpGeneratedItems(project, i.ProjectItems, remove);
  992. }
  993. else if(Util.isProjectItemFile(i))
  994. {
  995. removeCSharpGeneratedItems(i, remove);
  996. }
  997. }
  998. }
  999. public void buildProject(Project project, bool force, vsBuildScope scope, bool buildDependencies)
  1000. {
  1001. List<Project> builded = new List<Project>();
  1002. buildProject(project, force, null, scope, buildDependencies, ref builded);
  1003. }
  1004. public void buildProject(Project project, bool force, vsBuildScope scope, bool buildDependencies, ref List<Project> builded)
  1005. {
  1006. buildProject(project, force, null, scope, buildDependencies, ref builded);
  1007. }
  1008. public void buildProject(Project project, bool force, ProjectItem excludeItem, vsBuildScope scope, bool buildDependencies)
  1009. {
  1010. List<Project> builded = new List<Project>();
  1011. buildProject(project, force, excludeItem, scope, buildDependencies, ref builded);
  1012. }
  1013. public void buildProject(Project project, bool force, ProjectItem excludeItem, vsBuildScope scope, bool buildDependencies,
  1014. ref List<Project> builded)
  1015. {
  1016. if(project == null)
  1017. {
  1018. return;
  1019. }
  1020. if(!Util.isSliceBuilderEnabled(project))
  1021. {
  1022. return;
  1023. }
  1024. if(builded.Contains(project))
  1025. {
  1026. return;
  1027. }
  1028. if(_deleted.Count > 0)
  1029. {
  1030. return;
  1031. }
  1032. initializeProject(project);
  1033. builded.Add(project);
  1034. List<ProjectItem> buildItems = new List<ProjectItem>();
  1035. //
  1036. // When building a single project, we must first build projects
  1037. // that this project depends on.
  1038. //
  1039. if(vsBuildScope.vsBuildScopeProject == scope && buildDependencies)
  1040. {
  1041. BuildDependencies dependencies = _applicationObject.Solution.SolutionBuild.BuildDependencies;
  1042. for(int i = 0; i < dependencies.Count; ++i)
  1043. {
  1044. BuildDependency dp = dependencies.Item(i + 1);
  1045. if(dp == null)
  1046. {
  1047. continue;
  1048. }
  1049. if(dp.Project.Equals(project))
  1050. {
  1051. System.Array projects = dp.RequiredProjects as System.Array;
  1052. if(projects != null)
  1053. {
  1054. foreach(Project p in projects)
  1055. {
  1056. buildProject(p, force, vsBuildScope.vsBuildScopeProject, buildDependencies, ref builded);
  1057. }
  1058. }
  1059. }
  1060. }
  1061. }
  1062. if(Util.isVBProject(project))
  1063. {
  1064. //
  1065. // For VB projects we just build dependencies.
  1066. //
  1067. return;
  1068. }
  1069. DTE dte = Util.getCurrentDTE();
  1070. if(!_opening)
  1071. {
  1072. dte.StatusBar.Text = "Ice Add-in: building project '" + project.FullName + "'";
  1073. }
  1074. string msg = "------ Slice compilation started " + "Project: " + Util.getTraceProjectName(project) + " ------\n";
  1075. Util.write(project, Util.msgLevel.msgInfo, msg);
  1076. int verboseLevel = Util.getVerboseLevel(project);
  1077. DateTime now = DateTime.Now;
  1078. if(verboseLevel >= (int)Util.msgLevel.msgDebug)
  1079. {
  1080. Util.write(project, Util.msgLevel.msgDebug, "DEBUG Start Time: " + now.ToShortDateString() + " " +
  1081. now.ToLongTimeString() + "\n");
  1082. }
  1083. if(Util.isCSharpProject(project))
  1084. {
  1085. buildCSharpProject(project, force, excludeItem);
  1086. }
  1087. else if(Util.isCppProject(project))
  1088. {
  1089. buildCppProject(project, force, ref buildItems);
  1090. }
  1091. if(verboseLevel >= (int)Util.msgLevel.msgDebug)
  1092. {
  1093. System.TimeSpan t = System.DateTime.Now - now;
  1094. Util.write(project, Util.msgLevel.msgDebug, "DEBUG Output:\n");
  1095. Util.write(project, Util.msgLevel.msgDebug, "DEBUG Time Elapsed: " + t.ToString() + "\n");
  1096. }
  1097. if(hasErrors(project))
  1098. {
  1099. Util.write(project, Util.msgLevel.msgError,
  1100. "------ Slice compilation failed: Project: " + Util.getTraceProjectName(project) +" ------\n\n");
  1101. }
  1102. else
  1103. {
  1104. Util.write(project, Util.msgLevel.msgInfo,
  1105. "------ Slice compilation succeeded: Project: " + Util.getTraceProjectName(project) + " ------\n\n");
  1106. }
  1107. if(!_opening)
  1108. {
  1109. dte.StatusBar.Text = "Ready";
  1110. }
  1111. }
  1112. public bool buildCppProject(Project project, bool force, ref List<ProjectItem> buildedItems)
  1113. {
  1114. VCConfiguration conf = Util.getActiveVCConfiguration(project);
  1115. if(conf.ConfigurationType == ConfigurationTypes.typeGeneric ||
  1116. conf.ConfigurationType == ConfigurationTypes.typeUnknown)
  1117. {
  1118. string err = "Configuration Type: '" + conf.ConfigurationType.ToString() + "' not supported by Ice Visual Studio Add-in";
  1119. Util.write(project, Util.msgLevel.msgError,
  1120. "------ Slice compilation failed: Project: " + Util.getTraceProjectName(project) + " ------\n\n" +
  1121. err);
  1122. MessageBox.Show(err, "Ice Visual Studio Add-in", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1,
  1123. (MessageBoxOptions)0);
  1124. Connect.getBuilder().addError(project, "", TaskErrorCategory.Error, 0, 0, err);
  1125. return false;
  1126. }
  1127. VCCLCompilerTool compilerTool =
  1128. (VCCLCompilerTool)(((IVCCollection)conf.Tools).Item("VCCLCompilerTool"));
  1129. bool staticLib = conf.ConfigurationType == Microsoft.VisualStudio.VCProjectEngine.ConfigurationTypes.typeStaticLibrary;
  1130. LinkerAdapter linkerAdapter;
  1131. if(staticLib)
  1132. {
  1133. linkerAdapter = new StaticLinkerAdapter((VCLibrarianTool)(((IVCCollection)conf.Tools).Item("VCLibrarianTool")));
  1134. }
  1135. else
  1136. {
  1137. linkerAdapter = new DynamicLinkerAdapter((VCLinkerTool)(((IVCCollection)conf.Tools).Item("VCLinkerTool")));
  1138. }
  1139. if(!_opening)
  1140. {
  1141. Util.checkCppRunTimeLibrary(this, project, compilerTool, linkerAdapter);
  1142. }
  1143. string sliceCompiler = getSliceCompilerPath(project);
  1144. return buildCppProject(project, project.ProjectItems, sliceCompiler, force, ref buildedItems);
  1145. }
  1146. public bool buildCppProject(Project project, ProjectItems items, string sliceCompiler, bool force,
  1147. ref List<ProjectItem> buildedItems)
  1148. {
  1149. bool success = true;
  1150. List<ProjectItem> tmpItems = Util.clone(items);
  1151. foreach(ProjectItem i in tmpItems)
  1152. {
  1153. if(i == null)
  1154. {
  1155. continue;
  1156. }
  1157. if(Util.isProjectItemFilter(i))
  1158. {
  1159. if(!buildCppProject(project, i.ProjectItems, sliceCompiler, force, ref buildedItems))
  1160. {
  1161. success = false;
  1162. }
  1163. }
  1164. else if(Util.isProjectItemFile(i))
  1165. {
  1166. if(!buildCppProjectItem(project, i, sliceCompiler, force, ref buildedItems))
  1167. {
  1168. success = false;
  1169. }
  1170. }
  1171. }
  1172. return success;
  1173. }
  1174. public bool buildCppProjectItem(Project project, ProjectItem item, string sliceCompiler, bool force,
  1175. ref List<ProjectItem> buildedItems)
  1176. {
  1177. if(project == null)
  1178. {
  1179. return true;
  1180. }
  1181. if(item == null)
  1182. {
  1183. return true;
  1184. }
  1185. if(item.Name == null)
  1186. {
  1187. return true;
  1188. }
  1189. if(!Util.isSliceFilename(item.Name))
  1190. {
  1191. return true;
  1192. }
  1193. FileInfo iceFileInfo = new FileInfo(item.Properties.Item("FullPath").Value.ToString());
  1194. FileInfo hFileInfo = new FileInfo(getCppGeneratedFileName(project,
  1195. iceFileInfo.FullName, Util.getHeaderExt(project)));
  1196. FileInfo cppFileInfo = new FileInfo(Path.ChangeExtension(hFileInfo.FullName, Util.getSourceExt(project)));
  1197. string output = Path.GetDirectoryName(cppFileInfo.FullName);
  1198. return buildCppProjectItem(project, output, iceFileInfo, cppFileInfo, hFileInfo, sliceCompiler, force,
  1199. ref buildedItems);
  1200. }
  1201. public bool buildCppProjectItem(Project project, String output, FileSystemInfo ice, FileSystemInfo cpp,
  1202. FileSystemInfo h, string sliceCompiler, bool force,
  1203. ref List<ProjectItem> buildedItems)
  1204. {
  1205. bool updated = false;
  1206. bool success = false;
  1207. if(!h.Exists || !cpp.Exists)
  1208. {
  1209. updated = true;
  1210. }
  1211. else if(Util.findItem(h.FullName, project.ProjectItems) == null ||
  1212. Util.findItem(cpp.FullName, project.ProjectItems) == null)
  1213. {
  1214. updated = true;
  1215. }
  1216. else if(ice.LastWriteTime > h.LastWriteTime || ice.LastWriteTime > cpp.LastWriteTime)
  1217. {
  1218. if(!Directory.Exists(output))
  1219. {
  1220. Directory.CreateDirectory(output);
  1221. }
  1222. updated = true;
  1223. }
  1224. else
  1225. {
  1226. //
  1227. // Now check if any of the dependencies have changed.
  1228. //
  1229. DependenciesMap solutionDependenciesMap = getDependenciesMap();
  1230. if(solutionDependenciesMap.ContainsKey(project.FullName))
  1231. {
  1232. Dictionary<string, List<string>> dependenciesMap = solutionDependenciesMap[project.FullName];
  1233. if(dependenciesMap.ContainsKey(ice.FullName))
  1234. {
  1235. List<string> fileDependencies = dependenciesMap[ice.FullName];
  1236. foreach(string name in fileDependencies)
  1237. {
  1238. FileInfo dependency = new FileInfo(Util.absolutePath(project, name));
  1239. if(!dependency.Exists)
  1240. {
  1241. updated = true;
  1242. break;
  1243. }
  1244. if(dependency.LastWriteTime > cpp.LastWriteTime ||
  1245. dependency.LastWriteTime > h.LastWriteTime)
  1246. {
  1247. updated = true;
  1248. break;
  1249. }
  1250. }
  1251. }
  1252. }
  1253. }
  1254. Util.write(project, Util.msgLevel.msgInfo, ice.Name + ":\n");
  1255. if(updated || force)
  1256. {
  1257. if(!Directory.Exists(output))
  1258. {
  1259. Directory.CreateDirectory(output);
  1260. }
  1261. if(updateDependencies(project, null, ice.FullName, sliceCompiler) && updated)
  1262. {
  1263. Util.write(project, Util.msgLevel.msgInfo, " Generating C++ files: " + cpp.Name + ", " + h.Name + "\n");
  1264. if(runSliceCompiler(project, sliceCompiler, ice.FullName, output))
  1265. {
  1266. buildedItems.Add(Util.findItem(ice.FullName, project.ProjectItems));
  1267. success = true;
  1268. }
  1269. }
  1270. }
  1271. if(!updated)
  1272. {
  1273. if(!force)
  1274. {
  1275. Util.write(project, Util.msgLevel.msgInfo, " Dependencies data is up to date\n");
  1276. }
  1277. Util.write(project, Util.msgLevel.msgInfo, " Generated C++ files are up to date\n");
  1278. }
  1279. //
  1280. // Make sure generated files are part of project, and tracked by the FileTracker.
  1281. //
  1282. addCppGeneratedFiles(project, ice, cpp, h);
  1283. return !updated || success;
  1284. }
  1285. public void addCppGeneratedFiles(Project project, FileSystemInfo ice, FileSystemInfo cpp, FileSystemInfo h)
  1286. {
  1287. if(project == null)
  1288. {
  1289. return;
  1290. }
  1291. VCProject vcProject = (VCProject)project.Object;
  1292. if(File.Exists(cpp.FullName))
  1293. {
  1294. fileTracker().trackFile(project, ice.FullName, h.FullName);
  1295. VCFile file = Util.findVCFile((IVCCollection)vcProject.Files, cpp.Name, cpp.FullName);
  1296. if(file == null)
  1297. {
  1298. vcProject.AddFile(cpp.FullName);
  1299. }
  1300. }
  1301. if(File.Exists(h.FullName))
  1302. {
  1303. fileTracker().trackFile(project, ice.FullName, cpp.FullName);
  1304. VCFile file = Util.findVCFile((IVCCollection)vcProject.Files, h.Name, h.FullName);
  1305. if(file == null)
  1306. {
  1307. vcProject.AddFile(h.FullName);
  1308. }
  1309. }
  1310. }
  1311. public void buildCSharpProject(Project project, bool force)
  1312. {
  1313. buildCSharpProject(project, force, null);
  1314. }
  1315. public void buildCSharpProject(Project project, bool force, ProjectItem excludeItem)
  1316. {
  1317. string projectDir = Path.GetDirectoryName(project.FileName);
  1318. string sliceCompiler = getSliceCompilerPath(project);
  1319. buildCSharpProject(project, projectDir, project.ProjectItems, sliceCompiler, force, excludeItem);
  1320. }
  1321. public void buildCSharpProject(Project project, string projectDir, ProjectItems items, string sliceCompiler,
  1322. bool force, ProjectItem excludeItem)
  1323. {
  1324. List<ProjectItem> tmpItems = Util.clone(items);
  1325. foreach(ProjectItem i in tmpItems)
  1326. {
  1327. if(i == null || i == excludeItem)
  1328. {
  1329. continue;
  1330. }
  1331. if(Util.isProjectItemFolder(i))
  1332. {
  1333. buildCSharpProject(project, projectDir, i.ProjectItems, sliceCompiler, force, excludeItem);
  1334. }
  1335. else if(Util.isProjectItemFile(i))
  1336. {
  1337. buildCSharpProjectItem(project, i, sliceCompiler, force);
  1338. }
  1339. }
  1340. }
  1341. public static String getCppGeneratedFileName(Project project, String fullPath, string extension)
  1342. {
  1343. if(project == null || String.IsNullOrEmpty(fullPath))
  1344. {
  1345. return "";
  1346. }
  1347. if(!Util.isSliceFilename(fullPath))
  1348. {
  1349. return "";
  1350. }
  1351. string projectDir = Path.GetDirectoryName(project.FileName).Trim();
  1352. string outputAbsolutePath = Util.getProjectAbsoluteOutputDir(project);
  1353. string itemRelativePath = "";
  1354. //
  1355. // If source isn't inside project directory, we put the generated file in the
  1356. // root of our output directory.
  1357. //
  1358. if(!Path.GetFullPath(fullPath).StartsWith(Path.GetFullPath(projectDir),
  1359. StringComparison.CurrentCultureIgnoreCase))
  1360. {
  1361. itemRelativePath = Path.GetFileName(fullPath);
  1362. }
  1363. //
  1364. // If source file is in generated directory, just change the extension to the path.
  1365. //
  1366. else if(Path.GetFullPath(fullPath).StartsWith(outputAbsolutePath,
  1367. StringComparison.CurrentCultureIgnoreCase))
  1368. {
  1369. return Path.ChangeExtension(fullPath, extension);
  1370. }
  1371. else
  1372. {
  1373. itemRelativePath = Util.relativePath(project, Path.GetDirectoryName(fullPath));
  1374. }
  1375. if(String.IsNullOrEmpty(itemRelativePath))
  1376. {
  1377. return "";
  1378. }
  1379. string generatedDir = Path.GetDirectoryName(itemRelativePath);
  1380. string path = System.IO.Path.Combine(outputAbsolutePath, generatedDir);
  1381. return Path.GetFullPath(
  1382. Path.Combine(path, Path.ChangeExtension(Path.GetFileName(fullPath), extension))).Trim();
  1383. }
  1384. public static string getCSharpGeneratedFileName(Project project, ProjectItem item, string extension)
  1385. {
  1386. if(project == null || item == null || String.IsNullOrEmpty(extension))
  1387. {
  1388. return "";
  1389. }
  1390. string fullPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(project.FileName),
  1391. Util.getPathRelativeToProject(item)));
  1392. return getCSharpGeneratedFileName(project, fullPath, extension).Trim();
  1393. }
  1394. public static string getCSharpGeneratedFileName(Project project, string fullPath, string extension)
  1395. {
  1396. if(project == null || String.IsNullOrEmpty(fullPath) || String.IsNullOrEmpty(extension))
  1397. {
  1398. return "";
  1399. }
  1400. if(!Util.isSliceFilename(fullPath))
  1401. {
  1402. return "";
  1403. }
  1404. string projectDir = Path.GetDirectoryName(project.FileName);
  1405. string itemRelativePath = Util.relativePath(project, fullPath);
  1406. if(String.IsNullOrEmpty(itemRelativePath))
  1407. {
  1408. return "";
  1409. }
  1410. string outputAbsolutePath = Util.getProjectAbsoluteOutputDir(project);
  1411. //
  1412. // If source file is in generated directory, just change the extension to the path.
  1413. //
  1414. if(Path.GetFullPath(fullPath).StartsWith(outputAbsolutePath, StringComparison.CurrentCultureIgnoreCase))
  1415. {
  1416. return Path.ChangeExtension(fullPath, extension);
  1417. }
  1418. string generatedDir = Path.GetDirectoryName(itemRelativePath);
  1419. string path = Path.Combine(outputAbsolutePath, generatedDir);
  1420. return Path.GetFullPath(
  1421. Path.Combine(path, Path.ChangeExtension(Path.GetFileName(fullPath), extension))).Trim();
  1422. }
  1423. public bool buildCSharpProjectItem(Project project, ProjectItem item, string sliceCompiler, bool force)
  1424. {
  1425. if(project == null)
  1426. {
  1427. return true;
  1428. }
  1429. if(item == null)
  1430. {
  1431. return true;
  1432. }
  1433. if(item.Name == null)
  1434. {
  1435. return true;
  1436. }
  1437. if(!Util.isSliceFilename(item.Name))
  1438. {
  1439. return true;
  1440. }
  1441. FileInfo iceFileInfo = new FileInfo(item.Properties.Item("FullPath").Value.ToString());
  1442. FileInfo generatedFileInfo = new FileInfo(getCSharpGeneratedFileName(project, item, "cs"));
  1443. bool success = false;
  1444. bool updated = false;
  1445. if(!generatedFileInfo.Exists)
  1446. {
  1447. updated = true;
  1448. }
  1449. else if(iceFileInfo.LastWriteTime > generatedFileInfo.LastWriteTime)
  1450. {
  1451. updated = true;
  1452. }
  1453. else
  1454. {
  1455. //
  1456. // Now check if any of the dependencies have changed.
  1457. //
  1458. DependenciesMap solutionDependenciesMap = getDependenciesMap();
  1459. if(solutionDependenciesMap.ContainsKey(project.FullName))
  1460. {
  1461. Dictionary<string, List<string>> dependenciesMap = solutionDependenciesMap[project.FullName];
  1462. if(dependenciesMap.ContainsKey(iceFileInfo.FullName))
  1463. {
  1464. List<string> fileDependencies = dependenciesMap[iceFileInfo.FullName];
  1465. foreach(string name in fileDependencies)
  1466. {
  1467. FileInfo dependency =
  1468. new FileInfo(Util.absolutePath(project, name));
  1469. if(!dependency.Exists)
  1470. {
  1471. updated = true;
  1472. break;
  1473. }
  1474. if(dependency.LastWriteTime > generatedFileInfo.LastWriteTime)
  1475. {
  1476. updated = true;
  1477. break;
  1478. }
  1479. }
  1480. }
  1481. }
  1482. }
  1483. Util.write(project, Util.msgLevel.msgInfo, iceFileInfo.Name + ":\n");
  1484. if(updated || force)
  1485. {
  1486. if(updateDependencies(project, item, iceFileInfo.FullName, sliceCompiler) &&
  1487. updated)
  1488. {
  1489. Util.write(project, Util.msgLevel.msgInfo, " Generating C# file: " + generatedFileInfo.Name + "\n");
  1490. if(runSliceCompiler(project, sliceCompiler, iceFileInfo.FullName, generatedFileInfo.DirectoryName))
  1491. {
  1492. success = true;
  1493. }
  1494. }
  1495. }
  1496. if(!updated)
  1497. {
  1498. if(!force)
  1499. {
  1500. Util.write(project, Util.msgLevel.msgInfo, " Dependencies data is up to date\n");
  1501. }
  1502. Util.write(project, Util.msgLevel.msgInfo, " Generated C# files are up to date\n");
  1503. }
  1504. //
  1505. // Make sure generated files are part of project, and tracked by FileTracker.
  1506. //
  1507. addCSharpGeneratedFiles(project, iceFileInfo, generatedFileInfo);
  1508. return !updated || success;
  1509. }
  1510. private void addCSharpGeneratedFiles(Project project, FileInfo ice, FileInfo file)
  1511. {
  1512. if(File.Exists(file.FullName))
  1513. {
  1514. fileTracker().trackFile(project, ice.FullName, file.FullName);
  1515. ProjectItem generatedItem = Util.findItem(file.FullName, project.ProjectItems);
  1516. if(generatedItem == null)
  1517. {
  1518. project.ProjectItems.AddFromFile(file.FullName);
  1519. }
  1520. }
  1521. }
  1522. public static string getSliceCompilerPath(Project project)
  1523. {
  1524. string compiler = Util.slice2cpp;
  1525. if(Util.isCSharpProject(project))
  1526. {
  1527. compiler = Util.slice2cs;
  1528. }
  1529. if(!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("IceSourceHome")))
  1530. {
  1531. return Path.Combine(Environment.GetEnvironmentVariable("IceSourceHome"),
  1532. Path.Combine("cpp", Path.Combine("bin", compiler)));
  1533. }
  1534. string iceHome = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
  1535. if(iceHome.EndsWith("\\vsaddin", StringComparison.CurrentCultureIgnoreCase))
  1536. {
  1537. return Path.Combine(iceHome.Substring(0, iceHome.Length - "\\vsaddin".Length),
  1538. Path.Combine("bin", compiler));
  1539. }
  1540. if(iceHome.EndsWith("\\vsaddin\\bin", StringComparison.CurrentCultureIgnoreCase))
  1541. {
  1542. return Path.Combine(iceHome.Substring(0, iceHome.Length - "\\vsaddin\\bin".Length),
  1543. Path.Combine("cpp", Path.Combine("bin", compiler)));
  1544. }
  1545. throw new ArgumentException("Unable to determite Slice compiler location");
  1546. }
  1547. private static string getSliceCompilerArgs(Project project, string file, bool depend)
  1548. {
  1549. IncludePathList includes =
  1550. new IncludePathList(Util.getProjectProperty(project, Util.PropertyIceIncludePath));
  1551. string extraOpts = Util.getProjectProperty(project, Util.PropertyIceExtraOptions).Trim();
  1552. bool tie = Util.getProjectPropertyAsBool(project, Util.PropertyIceTie);
  1553. bool ice = Util.getProjectPropertyAsBool(project, Util.PropertyIcePrefix);
  1554. bool streaming = Util.getProjectPropertyAsBool(project, Util.PropertyIceStreaming);
  1555. bool checksum = Util.getProjectPropertyAsBool(project, Util.PropertyIceChecksum);
  1556. string args = "";
  1557. if(depend)
  1558. {
  1559. args += "--depend ";
  1560. }
  1561. if(Util.isCppProject(project))
  1562. {
  1563. String dllExportSymbol = Util.getProjectProperty(project, Util.PropertyIceDllExport);
  1564. if(!String.IsNullOrEmpty(dllExportSymbol))
  1565. {
  1566. args += "--dll-export=" + dllExportSymbol + " ";
  1567. }
  1568. String preCompiledHeader = Util.getPrecompileHeader(project, file);
  1569. if(!String.IsNullOrEmpty(preCompiledHeader))
  1570. {
  1571. args += "--add-header=" + Util.quote(preCompiledHeader) + " ";
  1572. }
  1573. }
  1574. args += "-I\"" + Util.getIceHome() + "\\slice\" ";
  1575. foreach(string i in includes)
  1576. {
  1577. if(String.IsNullOrEmpty(i))
  1578. {
  1579. continue;
  1580. }
  1581. String include = Util.expandEnvironmentVars(i);
  1582. if(include.EndsWith("\\", StringComparison.Ordinal) &&
  1583. include.Split(new char[]{'\\'}, StringSplitOptions.RemoveEmptyEntries).Length == 1)
  1584. {
  1585. include += ".";
  1586. }
  1587. if(include.EndsWith("\\", StringComparison.Ordinal) &&
  1588. !include.EndsWith("\\\\", StringComparison.Ordinal))
  1589. {
  1590. include += "\\";
  1591. }
  1592. args += "-I" + Util.quote(include) + " ";
  1593. }
  1594. if(!String.IsNullOrEmpty(extraOpts))
  1595. {
  1596. args += Util.expandEnvironmentVars(extraOpts) + " ";
  1597. }
  1598. if(tie && Util.isCSharpProject(project) && !Util.isSilverlightProject(project))
  1599. {
  1600. args += "--tie ";
  1601. }
  1602. if(ice)
  1603. {
  1604. args += "--ice ";
  1605. }
  1606. if(streaming)
  1607. {
  1608. args += "--stream ";
  1609. }
  1610. if(checksum)
  1611. {
  1612. args += "--checksum ";
  1613. }
  1614. return args;
  1615. }
  1616. public bool updateDependencies(Project project)
  1617. {
  1618. return updateDependencies(project, null);
  1619. }
  1620. public bool updateDependencies(Project project, ProjectItem excludeItem)
  1621. {
  1622. DependenciesMap dependenciesMap = getDependenciesMap();
  1623. dependenciesMap[project.FullName] = new Dictionary<string, List<string>>();
  1624. string sliceCompiler = getSliceCompilerPath(project);
  1625. return updateDependencies(project, project.ProjectItems, sliceCompiler, excludeItem);
  1626. }
  1627. public void cleanDependencies(Project project, string file)
  1628. {
  1629. if(project == null || file == null)
  1630. {
  1631. return;
  1632. }
  1633. if(String.IsNullOrEmpty(project.FullName))
  1634. {
  1635. return;
  1636. }
  1637. DependenciesMap dependenciesMap = getDependenciesMap();
  1638. if(!dependenciesMap.ContainsKey(project.FullName))
  1639. {
  1640. return;
  1641. }
  1642. Dictionary<string, List<string>> projectDependencies = dependenciesMap[project.FullName];
  1643. if(!projectDependencies.ContainsKey(file))
  1644. {
  1645. return;
  1646. }
  1647. projectDependencies.Remove(file);
  1648. dependenciesMap[project.FullName] = projectDependencies;
  1649. }
  1650. public bool updateDependencies(Project project, ProjectItems items, string sliceCompiler,
  1651. ProjectItem excludeItem)
  1652. {
  1653. bool success = true;
  1654. List<ProjectItem> tmpItems = Util.clone(items);
  1655. foreach(ProjectItem item in tmpItems)
  1656. {
  1657. if(item == null || item == excludeItem)
  1658. {
  1659. continue;
  1660. }
  1661. if(Util.isProjectItemFolder(item) || Util.isProjectItemFilter(item))
  1662. {
  1663. if(!updateDependencies(project, item.ProjectItems, sliceCompiler, excludeItem))
  1664. {
  1665. success = false;
  1666. }
  1667. }
  1668. else if(Util.isProjectItemFile(item))
  1669. {
  1670. if(!Util.isSliceFilename(item.Name))
  1671. {
  1672. continue;
  1673. }
  1674. string fullPath = item.Properties.Item("FullPath").Value.ToString();
  1675. if(!updateDependencies(project, item, fullPath, sliceCompiler))
  1676. {
  1677. success = false;
  1678. }
  1679. }
  1680. }
  1681. return success;
  1682. }
  1683. public bool updateDependencies(Project project, ProjectItem item, string file, string sliceCompiler)
  1684. {
  1685. Util.write(project, Util.msgLevel.msgInfo, " Computing dependencies\n");
  1686. if(!File.Exists(sliceCompiler))
  1687. {
  1688. Util.write(project, Util.msgLevel.msgError,
  1689. "'" + sliceCompiler + "' not found, review your Ice installation");
  1690. addError(project, file, TaskErrorCategory.Error, 0, 0,
  1691. "'" + sliceCompiler + "' not found, review your Ice installation");
  1692. return false;
  1693. }
  1694. string args = getSliceCompilerArgs(project, file, true) + " " + Util.quote(file);
  1695. System.Diagnostics.Process process = new System.Diagnostics.Process();
  1696. process.StartInfo.FileName = sliceCompiler;
  1697. process.StartInfo.Arguments = args;
  1698. process.StartInfo.CreateNoWindow = true;
  1699. process.StartInfo.UseShellExecute = false;
  1700. process.StartInfo.RedirectStandardError = true;
  1701. process.StartInfo.RedirectStandardOutput = true;
  1702. process.StartInfo.WorkingDirectory = Path.GetDirectoryName(project.FileName);
  1703. StreamReader reader = new StreamReader();
  1704. process.OutputDataReceived += new DataReceivedEventHandler(reader.appendData);
  1705. Util.write(project, Util.msgLevel.msgDebug,"DEBUG Command-line: " + sliceCompiler + " " + args + "\n");
  1706. try
  1707. {
  1708. process.Start();
  1709. }
  1710. catch(InvalidOperationException ex)
  1711. {
  1712. Util.write(project, Util.msgLevel.msgError,
  1713. "An exception was thrown when trying to start the Slice compiler\n" +
  1714. ex.ToString());
  1715. addError(project, file, TaskErrorCategory.Error, 0, 0,
  1716. "An exception was thrown when trying to start the Slice compiler\n" +
  1717. ex.ToString());
  1718. return false;
  1719. }
  1720. catch(System.ComponentModel.Win32Exception ex)
  1721. {
  1722. Util.write(project, Util.msgLevel.msgError,
  1723. "An exception was thrown when trying to start the Slice compiler\n" +
  1724. ex.ToString());
  1725. addError(project, file, TaskErrorCategory.Error, 0, 0,
  1726. "An exception was thrown when trying to start the Slice compiler\n" +
  1727. ex.ToString());
  1728. return false;
  1729. }
  1730. //
  1731. // When StandardError and StandardOutput are redirected, at least one
  1732. // should use asynchronous reads to prevent deadlocks when calling
  1733. // process.WaitForExit; the other can be read synchronously using ReadToEnd.
  1734. //
  1735. // See the Remarks section in the below link:
  1736. //
  1737. // http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standarderror.aspx
  1738. //
  1739. // Start the asynchronous read of the standard output stream.
  1740. process.BeginOutputReadLine();
  1741. // Read Standard error.
  1742. string stderr = process.StandardError.ReadToEnd();
  1743. process.WaitForExit();
  1744. if(parseErrors(project, sliceCompiler, file, stderr))
  1745. {
  1746. bringErrorsToFront();
  1747. process.Close();
  1748. if(Util.isCppProject(project))
  1749. {
  1750. removeCppGeneratedItems(project, file, false);
  1751. }
  1752. else if(Util.isCSharpProject(project))
  1753. {
  1754. removeCSharpGeneratedItems(item, false);
  1755. }
  1756. return false;
  1757. }
  1758. if(process.ExitCode != 0)
  1759. {
  1760. addError(project, file, TaskErrorCategory.Error, 0, 0,
  1761. "Slice compiler `" + sliceCompiler +
  1762. "' failed to start (error code " + process.ExitCode.ToString() + ")");
  1763. return false;
  1764. }
  1765. List<string> dependencies = new List<string>();
  1766. StringReader output = new StringReader(reader.data());
  1767. string line = null;
  1768. DependenciesMap dependenciesMap = getDependenciesMap();
  1769. if(!dependenciesMap.ContainsKey(project.FullName))
  1770. {
  1771. dependenciesMap[project.FullName] = new Dictionary<string, List<string>>();
  1772. }
  1773. Dictionary<string, List<string>> projectDeps = dependenciesMap[project.FullName];
  1774. bool firstLine = true;
  1775. while((line = output.ReadLine()) != null)
  1776. {
  1777. if(firstLine)
  1778. {
  1779. Util.write(project, Util.msgLevel.msgDebug, "DEBUG Output: " + line + "\n");
  1780. firstLine = false;
  1781. }
  1782. else
  1783. {
  1784. Util.write(project, Util.msgLevel.msgDebug, line + "\n");
  1785. }
  1786. if(!String.IsNullOrEmpty(line))
  1787. {
  1788. if(line.EndsWith(" \\", StringComparison.Ordinal))
  1789. {
  1790. line = line.Substring(0, line.Length - 2);
  1791. }
  1792. line = line.Trim();
  1793. //
  1794. // Unescape white spaces.
  1795. //
  1796. line = line.Replace("\\ ", " ");
  1797. if(line.EndsWith(".ice", StringComparison.CurrentCultureIgnoreCase) &&
  1798. !System.IO.Path.GetFileName(line).Trim().Equals(System.IO.Path.GetFileName(file)))
  1799. {
  1800. line = line.Replace('/', '\\');
  1801. dependencies.Add(line);
  1802. }
  1803. }
  1804. }
  1805. projectDeps[file] = dependencies;
  1806. dependenciesMap[project.FullName] = projectDeps;
  1807. process.Close();
  1808. return true;
  1809. }
  1810. public void initDocumentEvents()
  1811. {
  1812. try
  1813. {
  1814. // Csharp project item events.
  1815. _csProjectItemsEvents =
  1816. (EnvDTE.ProjectItemsEvents)_applicationObject.Events.GetObject("CSharpProjectItemsEvents");
  1817. if(_csProjectItemsEvents != null)
  1818. {
  1819. _csProjectItemsEvents.ItemAdded +=
  1820. new _dispProjectItemsEvents_ItemAddedEventHandler(csharpItemAdded);
  1821. _csProjectItemsEvents.ItemRemoved +=
  1822. new _dispProjectItemsEvents_ItemRemovedEventHandler(csharpItemRemoved);
  1823. }
  1824. }
  1825. catch(COMException)
  1826. {
  1827. // Can happen if the Visual Studio install don't support C#
  1828. }
  1829. try
  1830. {
  1831. // Cpp project item events.
  1832. _vcProjectItemsEvents =
  1833. (VCProjectEngineEvents)_applicationObject.Events.GetObject("VCProjectEngineEventsObject");
  1834. if (_vcProjectItemsEvents != null)
  1835. {
  1836. _vcProjectItemsEvents.ItemAdded +=
  1837. new _dispVCProjectEngineEvents_ItemAddedEventHandler(cppItemAdded);
  1838. _vcProjectItemsEvents.ItemRemoved +=
  1839. new _dispVCProjectEngineEvents_ItemRemovedEventHandler(cppItemRemoved);
  1840. }
  1841. }
  1842. catch(COMException)
  1843. {
  1844. // Can happen if the Visual Studio install don't support C++
  1845. }
  1846. // Visual Studio document events.
  1847. _docEvents = _applicationObject.Events.get_DocumentEvents(null);
  1848. if(_docEvents != null)
  1849. {
  1850. _docEvents.DocumentSaved += new _dispDocumentEvents_DocumentSavedEventHandler(documentSaved);
  1851. _docEvents.DocumentOpened += new _dispDocumentEvents_DocumentOpenedEventHandler(documentOpened);
  1852. }
  1853. }
  1854. public void removeDocumentEvents()
  1855. {
  1856. // Csharp project item events.
  1857. if(_csProjectItemsEvents != null)
  1858. {
  1859. _csProjectItemsEvents.ItemAdded -=
  1860. new _dispProjectItemsEvents_ItemAddedEventHandler(csharpItemAdded);
  1861. _csProjectItemsEvents.ItemRemoved -=
  1862. new _dispProjectItemsEvents_ItemRemovedEventHandler(csharpItemRemoved);
  1863. _csProjectItemsEvents = null;
  1864. }
  1865. // Cpp project item events.
  1866. if(_vcProjectItemsEvents != null)
  1867. {
  1868. _vcProjectItemsEvents.ItemAdded -=
  1869. new _dispVCProjectEngineEvents_ItemAddedEventHandler(cppItemAdded);
  1870. _vcProjectItemsEvents.ItemRemoved -=
  1871. new _dispVCProjectEngineEvents_ItemRemovedEventHandler(cppItemRemoved);
  1872. _vcProjectItemsEvents = null;
  1873. }
  1874. // Visual Studio document events.
  1875. if(_docEvents != null)
  1876. {
  1877. _docEvents.DocumentSaved -= new _dispDocumentEvents_DocumentSavedEventHandler(documentSaved);
  1878. _docEvents.DocumentOpened -= new _dispDocumentEvents_DocumentOpenedEventHandler(documentOpened);
  1879. _docEvents = null;
  1880. }
  1881. }
  1882. public Project getSelectedProject()
  1883. {
  1884. return Util.getSelectedProject(_applicationObject.DTE);
  1885. }
  1886. public Project getStartupProject()
  1887. {
  1888. try
  1889. {
  1890. Array projects = (Array)_applicationObject.Solution.SolutionBuild.StartupProjects;
  1891. Project p = Util.getProjectByNameOrFile(_applicationObject.Solution, projects.GetValue(0) as String);
  1892. if (p != null)
  1893. {
  1894. return p;
  1895. }
  1896. }
  1897. catch (COMException)
  1898. {
  1899. //
  1900. // Ignore could happen if called while solution is being initialized.
  1901. //
  1902. }
  1903. try
  1904. {
  1905. if(_applicationObject.Solution.Projects != null)
  1906. {
  1907. if(_applicationObject.Solution.Projects != null && _applicationObject.Solution.Projects.Count > 0)
  1908. {
  1909. return _applicationObject.Solution.Projects.Item(1) as Project;
  1910. }
  1911. }
  1912. }
  1913. catch(COMException)
  1914. {
  1915. //
  1916. // Ignore could happen if called while solution is being initialized.
  1917. //
  1918. }
  1919. return null;
  1920. }
  1921. public Project getActiveProject()
  1922. {
  1923. Array projects = null;
  1924. try
  1925. {
  1926. if(_applicationObject.ActiveSolutionProjects != null)
  1927. {
  1928. projects = (Array)_applicationObject.ActiveSolutionProjects;
  1929. if(projects != null && projects.Length > 0)
  1930. {
  1931. return projects.GetValue(0) as Project;
  1932. }
  1933. }
  1934. }
  1935. catch(COMException)
  1936. {
  1937. //
  1938. // Ignore could happen if called while solution is being initialized.
  1939. //
  1940. }
  1941. try
  1942. {
  1943. if(_applicationObject.Solution.Projects != null)
  1944. {
  1945. if(_applicationObject.Solution.Projects != null && _applicationObject.Solution.Projects.Count > 0)
  1946. {
  1947. return _applicationObject.Solution.Projects.Item(1) as Project;
  1948. }
  1949. }
  1950. }
  1951. catch(COMException)
  1952. {
  1953. //
  1954. // Ignore could happen if called while solution is being initialized.
  1955. //
  1956. }
  1957. return null;
  1958. }
  1959. private void removeDependency(Project project, String path)
  1960. {
  1961. DependenciesMap dependenciesMap = getDependenciesMap();
  1962. if(dependenciesMap.ContainsKey(project.FullName))
  1963. {
  1964. if(dependenciesMap[project.FullName].ContainsKey(path))
  1965. {
  1966. dependenciesMap[project.FullName].Remove(path);
  1967. }
  1968. }
  1969. }
  1970. private void cppItemRemoved(object obj, object parent)
  1971. {
  1972. try
  1973. {
  1974. if(obj == null)
  1975. {
  1976. return;
  1977. }
  1978. VCFile file = obj as VCFile;
  1979. if(file == null)
  1980. {
  1981. return;
  1982. }
  1983. if(file.project == null)
  1984. {
  1985. return;
  1986. }
  1987. if(!Util.isSliceFilename(file.Name))
  1988. {
  1989. return;
  1990. }
  1991. Project project = Util.findProject((VCProject)file.project);
  1992. if(project == null)
  1993. {
  1994. return;
  1995. }
  1996. if(!Util.isSliceBuilderEnabled(project))
  1997. {
  1998. return;
  1999. }
  2000. clearErrors(file.FullPath);
  2001. if(!_deleted.Contains(file.FullPath))
  2002. {
  2003. removeCppGeneratedItems(project, file.FullPath, true);
  2004. }
  2005. //
  2006. // It appears that the file is not actually removed from disk at this
  2007. // point. Thus we need to delay dependency updates until after delete,
  2008. // or after the remove command has been executed.
  2009. //
  2010. _deletedFile = file.FullPath;
  2011. }
  2012. catch(Exception ex)
  2013. {
  2014. Util.unexpectedExceptionWarning(ex);
  2015. throw;
  2016. }
  2017. }
  2018. void cppItemAdded(object obj, object parent)
  2019. {
  2020. try
  2021. {
  2022. if(obj == null)
  2023. {
  2024. return;
  2025. }
  2026. VCFile file = obj as VCFile;
  2027. if(file == null)
  2028. {
  2029. return;
  2030. }
  2031. if(file.project == null)
  2032. {
  2033. return;
  2034. }
  2035. if(!Util.isSliceFilename(file.Name))
  2036. {
  2037. return;
  2038. }
  2039. Project project = Util.findProject((VCProject)file.project);
  2040. if (project == null)
  2041. {
  2042. return;
  2043. }
  2044. string fullPath = file.FullPath;
  2045. if(!Util.isSliceBuilderEnabled(project))
  2046. {
  2047. return;
  2048. }
  2049. ProjectItem item = Util.findItem(fullPath, project.ProjectItems);
  2050. if(item == null)
  2051. {
  2052. return;
  2053. }
  2054. if(Util.isCppProject(project))
  2055. {
  2056. string cppPath = getCppGeneratedFileName(project, file.FullPath, Util.getSourceExt(project));
  2057. string hPath = Path.ChangeExtension(cppPath, "." + Util.getHeaderExt(project));
  2058. if(File.Exists(cppPath) || Util.hasItemNamed(project.ProjectItems, Path.GetFileName(cppPath)))
  2059. {
  2060. MessageBox.Show("A file named '" + Path.GetFileName(cppPath) +
  2061. "' already exists.\n" + "If you want to add '" +
  2062. Path.GetFileName(fullPath) + "' first remove " +
  2063. " '" + Path.GetFileName(cppPath) + "' and '" +
  2064. Path.GetFileName(hPath) + "'.",
  2065. "Ice Visual Studio Add-in",
  2066. MessageBoxButtons.OK,
  2067. MessageBoxIcon.Error,
  2068. MessageBoxDefaultButton.Button1,
  2069. (MessageBoxOptions)0);
  2070. _deleted.Add(fullPath);
  2071. return;
  2072. }
  2073. if(File.Exists(hPath) || Util.hasItemNamed(project.ProjectItems, Path.GetFileName(hPath)))
  2074. {
  2075. MessageBox.Show("A file named '" + Path.GetFileName(hPath) +
  2076. "' already exists.\n" + "If you want to add '" +
  2077. Path.GetFileName(fullPath) + "' first remove " +
  2078. " '" + Path.GetFileName(cppPath) + "' and '" +
  2079. Path.GetFileName(hPath) + "'.",
  2080. "Ice Visual Studio Add-in",
  2081. MessageBoxButtons.OK,
  2082. MessageBoxIcon.Error,
  2083. MessageBoxDefaultButton.Button1,
  2084. (MessageBoxOptions)0);
  2085. _deleted.Add(fullPath);
  2086. return;
  2087. }
  2088. }
  2089. clearErrors(project);
  2090. buildProject(project, false, vsBuildScope.vsBuildScopeProject, false);
  2091. }
  2092. catch(Exception ex)
  2093. {
  2094. Util.unexpectedExceptionWarning(ex);
  2095. throw;
  2096. }
  2097. }
  2098. private void csharpItemRemoved(ProjectItem item)
  2099. {
  2100. try
  2101. {
  2102. if(item == null)
  2103. {
  2104. return;
  2105. }
  2106. if(String.IsNullOrEmpty(item.Name) || item.ContainingProject == null)
  2107. {
  2108. return;
  2109. }
  2110. if(!Util.isSliceBuilderEnabled(item.ContainingProject))
  2111. {
  2112. return;
  2113. }
  2114. if(!Util.isSliceFilename(item.Name))
  2115. {
  2116. return;
  2117. }
  2118. string fullName = item.Properties.Item("FullPath").Value.ToString();
  2119. clearErrors(fullName);
  2120. removeCSharpGeneratedItems(item, true);
  2121. removeDependency(item.ContainingProject, fullName);
  2122. clearErrors(item.ContainingProject);
  2123. buildProject(item.ContainingProject, false, item, vsBuildScope.vsBuildScopeProject, false);
  2124. }
  2125. catch(Exception ex)
  2126. {
  2127. Util.unexpectedExceptionWarning(ex);
  2128. throw;
  2129. }
  2130. }
  2131. private void csharpItemAdded(ProjectItem item)
  2132. {
  2133. try
  2134. {
  2135. if(item == null)
  2136. {
  2137. return;
  2138. }
  2139. if(String.IsNullOrEmpty(item.Name) || item.ContainingProject == null)
  2140. {
  2141. return;
  2142. }
  2143. if(!Util.isSliceBuilderEnabled(item.ContainingProject))
  2144. {
  2145. return;
  2146. }
  2147. if(!Util.isSliceFilename(item.Name))
  2148. {
  2149. return;
  2150. }
  2151. string fullPath = item.Properties.Item("FullPath").Value.ToString();
  2152. Project project = item.ContainingProject;
  2153. String csPath = getCSharpGeneratedFileName(project, item, "cs");
  2154. ProjectItem csItem = Util.findItem(csPath, project.ProjectItems);
  2155. if(File.Exists(csPath) || csItem != null)
  2156. {
  2157. MessageBox.Show("A file named '" + Path.GetFileName(csPath) +
  2158. "' already exists.\n" + "If you want to add '" +
  2159. Path.GetFileName(fullPath) + "' first remove " +
  2160. " '" + Path.GetFileName(csPath) + "'.",
  2161. "Ice Visual Studio Add-in",
  2162. MessageBoxButtons.OK,
  2163. MessageBoxIcon.Error,
  2164. MessageBoxDefaultButton.Button1,
  2165. (MessageBoxOptions)0);
  2166. _deleted.Add(fullPath);
  2167. item.Remove();
  2168. return;
  2169. }
  2170. clearErrors(project);
  2171. buildProject(project, false, vsBuildScope.vsBuildScopeProject, false);
  2172. }
  2173. catch(Exception ex)
  2174. {
  2175. Util.unexpectedExceptionWarning(ex);
  2176. throw;
  2177. }
  2178. }
  2179. private static void removeCSharpGeneratedItems(ProjectItem item, bool remove)
  2180. {
  2181. if(item == null)
  2182. {
  2183. return;
  2184. }
  2185. if(String.IsNullOrEmpty(item.Name))
  2186. {
  2187. return;
  2188. }
  2189. if(!Util.isSliceFilename(item.Name))
  2190. {
  2191. return;
  2192. }
  2193. String generatedPath = getCSharpGeneratedFileName(item.ContainingProject, item, "cs");
  2194. if(String.IsNullOrEmpty(generatedPath))
  2195. {
  2196. return;
  2197. }
  2198. FileInfo generatedFileInfo = new FileInfo(generatedPath);
  2199. if(File.Exists(generatedFileInfo.FullName))
  2200. {
  2201. try
  2202. {
  2203. File.Delete(generatedFileInfo.FullName);
  2204. }
  2205. catch(System.SystemException)
  2206. {
  2207. // Can happen if the file is used by another process.
  2208. }
  2209. }
  2210. if(remove)
  2211. {
  2212. ProjectItem generated =
  2213. Util.findItem(generatedFileInfo.FullName, item.ContainingProject.ProjectItems);
  2214. if(generated != null)
  2215. {
  2216. generated.Remove();
  2217. }
  2218. }
  2219. }
  2220. private static void removeCppGeneratedItems(ProjectItems items, bool remove)
  2221. {
  2222. List<ProjectItem> tmpItems = Util.clone(items);
  2223. foreach(ProjectItem i in tmpItems)
  2224. {
  2225. if(Util.isProjectItemFile(i))
  2226. {
  2227. string path = i.Properties.Item("FullPath").Value.ToString();
  2228. if(!String.IsNullOrEmpty(path))
  2229. {
  2230. if(Util.isSliceFilename(path))
  2231. {
  2232. removeCppGeneratedItems(i, remove);
  2233. }
  2234. }
  2235. }
  2236. else if(Util.isProjectItemFilter(i))
  2237. {
  2238. removeCppGeneratedItems(i.ProjectItems, remove);
  2239. }
  2240. }
  2241. }
  2242. private static void removeCppGeneratedItems(ProjectItem item, bool remove)
  2243. {
  2244. if(item == null)
  2245. {
  2246. return;
  2247. }
  2248. if(String.IsNullOrEmpty(item.Name))
  2249. {
  2250. return;
  2251. }
  2252. if(!Util.isSliceFilename(item.Name))
  2253. {
  2254. return;
  2255. }
  2256. removeCppGeneratedItems(item.ContainingProject, item.Properties.Item("FullPath").Value.ToString(), remove);
  2257. }
  2258. // Delete from disk, remove from project if remove=true
  2259. public static void deleteProjectItem(Project project, string file, bool remove)
  2260. {
  2261. if(File.Exists(file))
  2262. {
  2263. try
  2264. {
  2265. File.Delete(file);
  2266. }
  2267. catch(System.SystemException)
  2268. {
  2269. // Can happen if the file is being used by another process.
  2270. }
  2271. }
  2272. if(remove)
  2273. {
  2274. ProjectItem generated = Util.findItem(file, project.ProjectItems);
  2275. if(generated != null)
  2276. {
  2277. generated.Remove();
  2278. }
  2279. }
  2280. }
  2281. public static void removeCppGeneratedItems(Project project, String slice, bool remove)
  2282. {
  2283. FileInfo hFileInfo = new FileInfo(getCppGeneratedFileName(project, slice, Util.getHeaderExt(project)));
  2284. FileInfo cppFileInfo = new FileInfo(Path.ChangeExtension(hFileInfo.FullName, Util.getSourceExt(project)));
  2285. deleteProjectItem(project, hFileInfo.FullName, remove);
  2286. deleteProjectItem(project, cppFileInfo.FullName, remove);
  2287. }
  2288. private bool runSliceCompiler(Project project, string sliceCompiler, string file, string outputDir)
  2289. {
  2290. if(!File.Exists(sliceCompiler))
  2291. {
  2292. Util.write(project, Util.msgLevel.msgError,
  2293. "'" + sliceCompiler + "' not found. Review 'Ice' installation.\n");
  2294. addError(project, file, TaskErrorCategory.Error, 0, 0,
  2295. "'" + sliceCompiler + "' not found. Review 'Ice' installation.\n");
  2296. return false;
  2297. }
  2298. string args = getSliceCompilerArgs(project, file, false);
  2299. if(!String.IsNullOrEmpty(outputDir))
  2300. {
  2301. if(outputDir.EndsWith("\\", StringComparison.Ordinal))
  2302. {
  2303. outputDir = outputDir.Replace("\\", "\\\\");
  2304. }
  2305. args += " --output-dir " + Util.quote(outputDir) + " ";
  2306. }
  2307. args += " " + Util.quote(file);
  2308. System.Diagnostics.Process process = new System.Diagnostics.Process();
  2309. process.StartInfo.FileName = sliceCompiler;
  2310. process.StartInfo.Arguments = args;
  2311. process.StartInfo.CreateNoWindow = true;
  2312. process.StartInfo.UseShellExecute = false;
  2313. process.StartInfo.RedirectStandardOutput = true;
  2314. process.StartInfo.RedirectStandardError = true;
  2315. process.StartInfo.WorkingDirectory = System.IO.Path.GetDirectoryName(project.FileName);
  2316. StreamReader reader = new StreamReader();
  2317. process.OutputDataReceived += new DataReceivedEventHandler(reader.appendData);
  2318. Util.write(project, Util.msgLevel.msgDebug, "DEBUG Command-line: " + sliceCompiler + " " + args + "\n");
  2319. if(!Directory.Exists(outputDir))
  2320. {
  2321. try
  2322. {
  2323. Directory.CreateDirectory(outputDir);
  2324. }
  2325. catch(System.IO.IOException ex)
  2326. {
  2327. Util.write(project, Util.msgLevel.msgError,
  2328. "An exception was thrown when trying to create the output directory.\n" +
  2329. ex.ToString());
  2330. addError(project, file, TaskErrorCategory.Error, 0, 0,
  2331. "An exception was thrown when trying to create the output directory.\n" + ex.ToString());
  2332. return false;
  2333. }
  2334. }
  2335. try
  2336. {
  2337. process.Start();
  2338. }
  2339. catch(InvalidOperationException ex)
  2340. {
  2341. Util.write(project, Util.msgLevel.msgError,
  2342. "An exception was thrown when trying to start the Slice compiler\n" +
  2343. ex.ToString());
  2344. addError(project, file, TaskErrorCategory.Error, 0, 0,
  2345. "An exception was thrown when trying to start the Slice compiler\n" +
  2346. ex.ToString());
  2347. return false;
  2348. }
  2349. catch(System.ComponentModel.Win32Exception ex)
  2350. {
  2351. Util.write(project, Util.msgLevel.msgError,
  2352. "An exception was thrown when trying to start the Slice compiler\n" +
  2353. ex.ToString());
  2354. addError(project, file, TaskErrorCategory.Error, 0, 0,
  2355. "An exception was thrown when trying to start the Slice compiler\n" +
  2356. ex.ToString());
  2357. return false;
  2358. }
  2359. //
  2360. // When StandardError and StandardOutput are redirected, at least one
  2361. // should use asynchronous reads to prevent deadlocks when calling
  2362. // process.WaitForExit; the other can be read synchronously using ReadToEnd.
  2363. //
  2364. // See the Remarks section in the below link:
  2365. //
  2366. // http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standarderror.aspx
  2367. //
  2368. string stderr = process.StandardError.ReadToEnd();
  2369. // Start the asynchronous read of the standard output stream.
  2370. process.BeginOutputReadLine();
  2371. process.WaitForExit();
  2372. if(process.ExitCode != 0)
  2373. {
  2374. addError(project, file, TaskErrorCategory.Error, 0, 0, "Slice compiler `" + sliceCompiler +
  2375. "' failed to start (error code " + process.ExitCode.ToString() + ")");
  2376. return false;
  2377. }
  2378. bool hasErrors = parseErrors(project, sliceCompiler, file, stderr);
  2379. process.Close();
  2380. if(hasErrors)
  2381. {
  2382. bringErrorsToFront();
  2383. if(Util.isCppProject(project))
  2384. {
  2385. removeCppGeneratedItems(project, file, false);
  2386. }
  2387. else if(Util.isCSharpProject(project))
  2388. {
  2389. ProjectItem item = Util.findItem(file, project.ProjectItems);
  2390. if(item != null)
  2391. {
  2392. removeCSharpGeneratedItems(item, false);
  2393. }
  2394. }
  2395. }
  2396. return !hasErrors;
  2397. }
  2398. private bool parseErrors(Project project, string sliceCompiler, string file, string stderr)
  2399. {
  2400. bool hasErrors = false;
  2401. StringReader strer = new StringReader(stderr);
  2402. string errorMessage = strer.ReadLine();
  2403. bool firstLine = true;
  2404. while(!String.IsNullOrEmpty(errorMessage))
  2405. {
  2406. if(errorMessage.StartsWith(sliceCompiler, StringComparison.Ordinal))
  2407. {
  2408. hasErrors = true;
  2409. String message = strer.ReadLine();
  2410. while(!String.IsNullOrEmpty(message))
  2411. {
  2412. message = message.Trim();
  2413. if(message.StartsWith("Usage:", StringComparison.CurrentCultureIgnoreCase))
  2414. {
  2415. break;
  2416. }
  2417. errorMessage += "\n" + message;
  2418. message = strer.ReadLine();
  2419. }
  2420. Util.write(project, Util.msgLevel.msgError, errorMessage + "\n");
  2421. addError(project, file, TaskErrorCategory.Error, 0, 0, errorMessage.Replace("error:", ""));
  2422. break;
  2423. }
  2424. int i = errorMessage.IndexOf(':');
  2425. if(i == -1)
  2426. {
  2427. if(firstLine)
  2428. {
  2429. errorMessage += strer.ReadToEnd();
  2430. Util.write(project, Util.msgLevel.msgError, errorMessage + "\n");
  2431. addError(project, "", TaskErrorCategory.Error, 1, 1, errorMessage);
  2432. hasErrors = true;
  2433. break;
  2434. }
  2435. errorMessage = strer.ReadLine();
  2436. continue;
  2437. }
  2438. Util.write(project, Util.msgLevel.msgError, errorMessage + "\n");
  2439. if(errorMessage.StartsWith(" ", StringComparison.Ordinal)) // Still the same mcpp warning
  2440. {
  2441. errorMessage = strer.ReadLine();
  2442. continue;
  2443. }
  2444. errorMessage = errorMessage.Trim();
  2445. firstLine = false;
  2446. i = errorMessage.IndexOf(':', i + 1);
  2447. if(i == -1)
  2448. {
  2449. errorMessage = strer.ReadLine();
  2450. continue;
  2451. }
  2452. string f = errorMessage.Substring(0, i);
  2453. if(String.IsNullOrEmpty(f))
  2454. {
  2455. errorMessage = strer.ReadLine();
  2456. continue;
  2457. }
  2458. if(!File.Exists(f))
  2459. {
  2460. errorMessage = strer.ReadLine();
  2461. continue;
  2462. }
  2463. errorMessage = errorMessage.Substring(i + 1, errorMessage.Length - i - 1);
  2464. i = errorMessage.IndexOf(':');
  2465. string n = errorMessage.Substring(0, i);
  2466. int l;
  2467. try
  2468. {
  2469. l = Int16.Parse(n, CultureInfo.InvariantCulture);
  2470. }
  2471. catch(OverflowException)
  2472. {
  2473. l = 0;
  2474. }
  2475. catch(FormatException)
  2476. {
  2477. l = 0;
  2478. }
  2479. catch(ArgumentException)
  2480. {
  2481. l = 0;
  2482. }
  2483. errorMessage = errorMessage.Substring(i + 1, errorMessage.Length - i - 1).Trim();
  2484. if(errorMessage.Equals("warning: End of input with no newline, supplemented newline"))
  2485. {
  2486. errorMessage = strer.ReadLine();
  2487. continue;
  2488. }
  2489. if(!String.IsNullOrEmpty(errorMessage))
  2490. {
  2491. //
  2492. // Display only errors from this file or files outside the project.
  2493. //
  2494. bool currentFile = Util.equalPath(f, file, Path.GetDirectoryName(project.FileName));
  2495. bool found = Util.findItem(f, project.ProjectItems) != null;
  2496. TaskErrorCategory category = TaskErrorCategory.Error;
  2497. if(errorMessage.StartsWith("warning:", StringComparison.CurrentCultureIgnoreCase))
  2498. {
  2499. category = TaskErrorCategory.Warning;
  2500. }
  2501. else
  2502. {
  2503. hasErrors = true;
  2504. }
  2505. if(currentFile || !found)
  2506. {
  2507. if(found)
  2508. {
  2509. addError(project, file, category, l, 1, errorMessage);
  2510. }
  2511. else
  2512. {
  2513. Util.write(project, Util.msgLevel.msgError,
  2514. "from file: " + f + "\n" + errorMessage + "\n");
  2515. addError(project, file, category, l, 1, "from file: " + f + "\n" + errorMessage);
  2516. }
  2517. }
  2518. }
  2519. errorMessage = strer.ReadLine();
  2520. }
  2521. return hasErrors;
  2522. }
  2523. public CommandBar projectCommandBar()
  2524. {
  2525. return findCommandBar(new Guid("{D309F791-903F-11D0-9EFC-00A0C911004F}"), 1026);
  2526. }
  2527. public CommandBar findCommandBar(Guid guidCmdGroup, uint menuID)
  2528. {
  2529. // Retrieve IVsProfferComands via DTE's IOleServiceProvider interface
  2530. IOleServiceProvider sp = (IOleServiceProvider)_applicationObject;
  2531. Guid guidSvc = typeof(IVsProfferCommands).GUID;
  2532. object objService;
  2533. int rc = sp.QueryService(ref guidSvc, ref guidSvc, out objService);
  2534. if(ErrorHandler.Failed(rc))
  2535. {
  2536. try
  2537. {
  2538. ErrorHandler.ThrowOnFailure(rc);
  2539. }
  2540. catch(Exception ex)
  2541. {
  2542. Util.unexpectedExceptionWarning(ex);
  2543. throw;
  2544. }
  2545. }
  2546. IVsProfferCommands vsProfferCmds = (IVsProfferCommands)objService;
  2547. return vsProfferCmds.FindCommandBar(IntPtr.Zero, ref guidCmdGroup, menuID) as CommandBar;
  2548. }
  2549. [ComImport,Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
  2550. InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
  2551. internal interface IOleServiceProvider
  2552. {
  2553. [PreserveSig]
  2554. int QueryService([In]ref Guid guidService, [In]ref Guid riid,
  2555. [MarshalAs(UnmanagedType.Interface)] out System.Object obj);
  2556. }
  2557. private void buildBegin(vsBuildScope scope, vsBuildAction action)
  2558. {
  2559. if(action == vsBuildAction.vsBuildActionBuild || action == vsBuildAction.vsBuildActionRebuildAll)
  2560. {
  2561. //
  2562. // Ensure slice compiler is only run once for parallel builds;
  2563. // no need to lock, this is always called from main thread.
  2564. //
  2565. if(!_sliceBuild)
  2566. {
  2567. _sliceBuild = true;
  2568. }
  2569. else
  2570. {
  2571. return;
  2572. }
  2573. }
  2574. try
  2575. {
  2576. string projectName = null;
  2577. if(commandLine)
  2578. {
  2579. projectName = Util.getCommandLineArgument("/Project");
  2580. }
  2581. _building = true;
  2582. _buildScope = scope;
  2583. Project project = null;
  2584. if(String.IsNullOrEmpty(projectName))
  2585. {
  2586. project = getSelectedProject();
  2587. }
  2588. else
  2589. {
  2590. project = Util.getProjectByNameOrFile(_applicationObject.Solution, projectName);
  2591. }
  2592. if(action == vsBuildAction.vsBuildActionBuild || action == vsBuildAction.vsBuildActionRebuildAll)
  2593. {
  2594. if(scope.Equals(vsBuildScope.vsBuildScopeProject) ||
  2595. (project != null && project.Kind.Equals(EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder)))
  2596. {
  2597. List<Project> projects = new List<Project>();
  2598. if(project.Kind.Equals(EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder))
  2599. {
  2600. projects = Util.solutionFolderProjects(project);
  2601. }
  2602. else
  2603. {
  2604. projects.Add(project);
  2605. }
  2606. foreach(Project p in projects)
  2607. {
  2608. _buildProject = p;
  2609. if(p == null)
  2610. {
  2611. continue;
  2612. }
  2613. clearErrors(p);
  2614. if(action == vsBuildAction.vsBuildActionRebuildAll)
  2615. {
  2616. cleanProject(p, false);
  2617. }
  2618. buildProject(p, false, scope, true);
  2619. if(hasErrors(p))
  2620. {
  2621. bringErrorsToFront();
  2622. Util.write(project, Util.msgLevel.msgError,
  2623. "------ Slice compilation contains errors. Build canceled. ------\n");
  2624. if (_connectMode == ext_ConnectMode.ext_cm_CommandLine)
  2625. {
  2626. // Is this the best we can do? Is there a clean way to exit?
  2627. Environment.Exit(-1);
  2628. }
  2629. _applicationObject.ExecuteCommand("Build.Cancel", "");
  2630. }
  2631. }
  2632. }
  2633. else
  2634. {
  2635. clearErrors();
  2636. List<Project> projects = Util.buildOrder(_applicationObject.Solution);
  2637. foreach(Project p in projects)
  2638. {
  2639. if(p != null)
  2640. {
  2641. if(!Util.isSliceBuilderEnabled(p))
  2642. {
  2643. continue;
  2644. }
  2645. if(action == vsBuildAction.vsBuildActionRebuildAll)
  2646. {
  2647. cleanProject(p, false);
  2648. }
  2649. buildProject(p, false, scope, false);
  2650. }
  2651. }
  2652. if(hasErrors())
  2653. {
  2654. bringErrorsToFront();
  2655. Util.write(null, Util.msgLevel.msgError,
  2656. "------ Slice compilation contains errors. Build canceled. ------\n");
  2657. if(_connectMode == ext_ConnectMode.ext_cm_CommandLine)
  2658. {
  2659. // Is this the best we can do? Is there a clean way to exit?
  2660. Environment.Exit(-1);
  2661. }
  2662. _applicationObject.ExecuteCommand("Build.Cancel", "");
  2663. }
  2664. }
  2665. }
  2666. else if(action == vsBuildAction.vsBuildActionClean)
  2667. {
  2668. if(scope.Equals(vsBuildScope.vsBuildScopeProject) ||
  2669. (project != null && project.Kind.Equals(EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder)))
  2670. {
  2671. List<Project> projects = new List<Project>();
  2672. if (project.Kind.Equals(EnvDTE80.ProjectKinds.vsProjectKindSolutionFolder))
  2673. {
  2674. projects = Util.solutionFolderProjects(project);
  2675. }
  2676. else
  2677. {
  2678. projects.Add(project);
  2679. }
  2680. foreach(Project p in projects)
  2681. {
  2682. _buildProject = p;
  2683. if (p == null)
  2684. {
  2685. continue;
  2686. }
  2687. cleanProject(p, false);
  2688. }
  2689. }
  2690. else
  2691. {
  2692. List<Project> projects = Util.buildOrder(_applicationObject.Solution);
  2693. foreach(Project p in projects)
  2694. {
  2695. if (p == null)
  2696. {
  2697. continue;
  2698. }
  2699. cleanProject(p, false);
  2700. }
  2701. }
  2702. }
  2703. }
  2704. catch(Exception ex)
  2705. {
  2706. Util.unexpectedExceptionWarning(ex);
  2707. throw;
  2708. }
  2709. return;
  2710. }
  2711. //
  2712. // Initialize slice builder error list provider
  2713. //
  2714. private void initErrorListProvider()
  2715. {
  2716. _errors = new List<ErrorTask>();
  2717. _errorListProvider = new Microsoft.VisualStudio.Shell.ErrorListProvider(_serviceProvider);
  2718. _errorListProvider.ProviderName = "Slice Error Provider";
  2719. _errorListProvider.ProviderGuid = new Guid("B8DA84E8-7AE3-4c71-8E43-F273A20D40D1");
  2720. _errorListProvider.Show();
  2721. }
  2722. //
  2723. // Remove all errors from slice builder error list provider
  2724. //
  2725. private void clearErrors()
  2726. {
  2727. _errorCount = 0;
  2728. _errors.Clear();
  2729. _errorListProvider.Tasks.Clear();
  2730. }
  2731. private void clearErrors(Project project)
  2732. {
  2733. if(project == null || _errors == null)
  2734. {
  2735. return;
  2736. }
  2737. List<ErrorTask> remove = new List<ErrorTask>();
  2738. foreach(ErrorTask error in _errors)
  2739. {
  2740. if(!error.HierarchyItem.Equals(getProjectHierarchy(project)))
  2741. {
  2742. continue;
  2743. }
  2744. if(!_errorListProvider.Tasks.Contains(error))
  2745. {
  2746. continue;
  2747. }
  2748. remove.Add(error);
  2749. _errorListProvider.Tasks.Remove(error);
  2750. }
  2751. foreach(ErrorTask error in remove)
  2752. {
  2753. _errors.Remove(error);
  2754. }
  2755. }
  2756. private void clearErrors(String file)
  2757. {
  2758. if(file == null || _errors == null)
  2759. {
  2760. return;
  2761. }
  2762. List<ErrorTask> remove = new List<ErrorTask>();
  2763. foreach(ErrorTask error in _errors)
  2764. {
  2765. if(error.Document.Equals(file, StringComparison.CurrentCultureIgnoreCase))
  2766. {
  2767. remove.Add(error);
  2768. _errorListProvider.Tasks.Remove(error);
  2769. }
  2770. }
  2771. foreach(ErrorTask error in remove)
  2772. {
  2773. _errors.Remove(error);
  2774. }
  2775. }
  2776. private IVsHierarchy getProjectHierarchy(Project project)
  2777. {
  2778. IVsSolution ivSSolution = getIVsSolution();
  2779. IVsHierarchy hierarchy = null;
  2780. if(ivSSolution != null)
  2781. {
  2782. int hr = ivSSolution.GetProjectOfUniqueName(project.UniqueName, out hierarchy);
  2783. if(ErrorHandler.Failed(hr))
  2784. {
  2785. try
  2786. {
  2787. ErrorHandler.ThrowOnFailure(hr);
  2788. }
  2789. catch(Exception ex)
  2790. {
  2791. Util.write(project, Util.msgLevel.msgError, ex.ToString() + "\n");
  2792. Util.unexpectedExceptionWarning(ex);
  2793. throw;
  2794. }
  2795. }
  2796. }
  2797. return hierarchy;
  2798. }
  2799. //
  2800. // Add an error to slice builder error list provider.
  2801. //
  2802. public void addError(Project project, string file, TaskErrorCategory category, int line, int column,
  2803. string text)
  2804. {
  2805. IVsHierarchy hierarchy = getProjectHierarchy(project);
  2806. ErrorTask errorTask = new ErrorTask();
  2807. errorTask.ErrorCategory = category;
  2808. // Visual Studio uses indexes starting at 0
  2809. // while the automation model uses indexes starting at 1
  2810. errorTask.Line = line - 1;
  2811. errorTask.Column = column - 1;
  2812. if(hierarchy != null)
  2813. {
  2814. errorTask.HierarchyItem = hierarchy;
  2815. }
  2816. errorTask.Navigate += new EventHandler(errorTaskNavigate);
  2817. errorTask.Document = file;
  2818. errorTask.Category = TaskCategory.BuildCompile;
  2819. errorTask.Text = text;
  2820. _errors.Add(errorTask);
  2821. _errorListProvider.Tasks.Add(errorTask);
  2822. if(category == TaskErrorCategory.Error)
  2823. {
  2824. ++_errorCount;
  2825. }
  2826. }
  2827. //
  2828. // True if there were any errors in the last slice compilation.
  2829. //
  2830. private bool hasErrors()
  2831. {
  2832. return _errorCount > 0;
  2833. }
  2834. private bool hasErrors(Project project)
  2835. {
  2836. if(project == null || _errors == null)
  2837. {
  2838. return false;
  2839. }
  2840. bool errors = false;
  2841. foreach(ErrorTask error in _errors)
  2842. {
  2843. if(error.HierarchyItem.Equals(getProjectHierarchy(project)))
  2844. {
  2845. if(error.ErrorCategory == TaskErrorCategory.Error)
  2846. {
  2847. errors = true;
  2848. break;
  2849. }
  2850. }
  2851. }
  2852. return errors;
  2853. }
  2854. private const string buildOutputPaneGuid = "{1BD8A850-02D1-11d1-BEE7-00A0C913D1F8}";
  2855. public OutputWindowPane buildOutput()
  2856. {
  2857. if(_output == null)
  2858. {
  2859. OutputWindow window = (OutputWindow)_applicationObject.Windows.Item(
  2860. EnvDTE.Constants.vsWindowKindOutput).Object;
  2861. foreach(OutputWindowPane w in window.OutputWindowPanes)
  2862. {
  2863. if(w.Guid.Equals(buildOutputPaneGuid, StringComparison.CurrentCultureIgnoreCase))
  2864. {
  2865. _output = w;
  2866. break;
  2867. }
  2868. }
  2869. }
  2870. return _output;
  2871. }
  2872. public ext_ConnectMode connectMode()
  2873. {
  2874. return _connectMode;
  2875. }
  2876. //
  2877. // Force the error list to show.
  2878. //
  2879. private void bringErrorsToFront()
  2880. {
  2881. if(_errorListProvider == null)
  2882. {
  2883. return;
  2884. }
  2885. _errorListProvider.BringToFront();
  2886. _errorListProvider.ForceShowErrors();
  2887. }
  2888. //
  2889. // Navigate to a file when the error is clicked.
  2890. //
  2891. private void errorTaskNavigate(object sender, EventArgs e)
  2892. {
  2893. try
  2894. {
  2895. ErrorTask task = (ErrorTask)sender;
  2896. task.Line += 1;
  2897. _errorListProvider.Navigate(task, new Guid(EnvDTE.Constants.vsViewKindTextView));
  2898. task.Line -= 1;
  2899. }
  2900. catch(Exception ex)
  2901. {
  2902. Util.unexpectedExceptionWarning(ex);
  2903. throw;
  2904. }
  2905. }
  2906. private DependenciesMap
  2907. getDependenciesMap()
  2908. {
  2909. if(_dependenciesMap == null)
  2910. {
  2911. _dependenciesMap = new DependenciesMap();
  2912. }
  2913. return _dependenciesMap;
  2914. }
  2915. private List<Project>
  2916. getRebuildProjects()
  2917. {
  2918. if(_rebuildProjects == null)
  2919. {
  2920. _rebuildProjects = new List<Project>();
  2921. }
  2922. return _rebuildProjects;
  2923. }
  2924. private IVsTrackProjectDocuments2 GetTrackProjectDocuments()
  2925. {
  2926. // get IServiceProvider (OLE version, not .NET version) from DTE object
  2927. IOleServiceProvider sp = (IOleServiceProvider)_applicationObject;
  2928. // retrieve IVsTrackProjectDocuments2 interface via QueryService
  2929. Guid guidSP = typeof(SVsTrackProjectDocuments).GUID;
  2930. Guid guidIID = typeof(IVsTrackProjectDocuments2).GUID;
  2931. object ptrUnknown;
  2932. int rc = sp.QueryService(ref guidSP, ref guidIID, out ptrUnknown);
  2933. if(ErrorHandler.Failed(rc))
  2934. {
  2935. try
  2936. {
  2937. ErrorHandler.ThrowOnFailure(rc);
  2938. }
  2939. catch(Exception ex)
  2940. {
  2941. Util.unexpectedExceptionWarning(ex);
  2942. throw;
  2943. }
  2944. }
  2945. IVsTrackProjectDocuments2 vsTrackProjDocs = (IVsTrackProjectDocuments2)ptrUnknown;
  2946. return vsTrackProjDocs;
  2947. }
  2948. public void beginTrackDocumentEvents()
  2949. {
  2950. int rc = GetTrackProjectDocuments().AdviseTrackProjectDocumentsEvents(this, out _dwCookie);
  2951. if(ErrorHandler.Failed(rc))
  2952. {
  2953. try
  2954. {
  2955. ErrorHandler.ThrowOnFailure(rc);
  2956. }
  2957. catch(Exception ex)
  2958. {
  2959. Util.unexpectedExceptionWarning(ex);
  2960. throw;
  2961. }
  2962. }
  2963. }
  2964. public void endTrackDocumentEvents()
  2965. {
  2966. int rc = GetTrackProjectDocuments().UnadviseTrackProjectDocumentsEvents(_dwCookie);
  2967. if(ErrorHandler.Failed(rc))
  2968. {
  2969. try
  2970. {
  2971. ErrorHandler.ThrowOnFailure(rc);
  2972. }
  2973. catch(Exception ex)
  2974. {
  2975. Util.unexpectedExceptionWarning(ex);
  2976. throw;
  2977. }
  2978. }
  2979. }
  2980. #region IVsTrackProjectDocumentsEvents2 Members
  2981. public int OnAfterAddDirectoriesEx(int cProjects, int cDirectories, IVsProject[] rgpProjects,
  2982. int[] rgFirstIndices, string[] rgpszMkDocuments,
  2983. VSADDDIRECTORYFLAGS[] rgFlags)
  2984. {
  2985. return 0;
  2986. }
  2987. public int OnAfterAddFilesEx(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices,
  2988. string[] rgpszMkDocuments, VSADDFILEFLAGS[] rgFlags)
  2989. {
  2990. return 0;
  2991. }
  2992. public int OnAfterRemoveDirectories(int cProjects, int cDirectories, IVsProject[] rgpProjects,
  2993. int[] rgFirstIndices, string[] rgpszMkDocuments,
  2994. VSREMOVEDIRECTORYFLAGS[] rgFlags)
  2995. {
  2996. return 0;
  2997. }
  2998. public int OnAfterRemoveFiles(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices,
  2999. string[] rgpszMkDocuments, VSREMOVEFILEFLAGS[] rgFlags)
  3000. {
  3001. return 0;
  3002. }
  3003. public int OnAfterRenameDirectories(int cProjects, int cDirs, IVsProject[] rgpProjects, int[] rgFirstIndices,
  3004. string[] rgszMkOldNames, string[] rgszMkNewNames,
  3005. VSRENAMEDIRECTORYFLAGS[] rgFlags)
  3006. {
  3007. return 0;
  3008. }
  3009. public int OnAfterRenameFiles(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices,
  3010. string[] oldNames, string[] newNames, VSRENAMEFILEFLAGS[] rgFlags)
  3011. {
  3012. foreach(string newName in newNames)
  3013. {
  3014. if(!Util.isSliceFilename(newName))
  3015. {
  3016. continue;
  3017. }
  3018. ProjectItem item = Util.findItem(newName);
  3019. if(item == null)
  3020. {
  3021. continue;
  3022. }
  3023. Project project = item.ContainingProject;
  3024. if(project == null)
  3025. {
  3026. continue;
  3027. }
  3028. if(!Util.isSliceBuilderEnabled(project))
  3029. {
  3030. continue;
  3031. }
  3032. buildProject(project, false, vsBuildScope.vsBuildScopeProject, false);
  3033. }
  3034. return 0;
  3035. }
  3036. public int OnAfterSccStatusChanged(int cProjects, int cFiles, IVsProject[] rgpProjects, int[] rgFirstIndices,
  3037. string[] rgpszMkDocuments, uint[] rgdwSccStatus)
  3038. {
  3039. return 0;
  3040. }
  3041. public int OnQueryAddDirectories(IVsProject pProject, int cDirectories, string[] rgpszMkDocuments,
  3042. VSQUERYADDDIRECTORYFLAGS[] rgFlags,
  3043. VSQUERYADDDIRECTORYRESULTS[] pSummaryResult,
  3044. VSQUERYADDDIRECTORYRESULTS[] rgResults)
  3045. {
  3046. return 0;
  3047. }
  3048. public int OnQueryAddFiles(IVsProject pProject, int cFiles, string[] rgpszMkDocuments,
  3049. VSQUERYADDFILEFLAGS[] rgFlags, VSQUERYADDFILERESULTS[] pSummaryResult,
  3050. VSQUERYADDFILERESULTS[] rgResults)
  3051. {
  3052. return 0;
  3053. }
  3054. public int OnQueryRemoveDirectories(IVsProject pProject, int cDirectories, string[] rgpszMkDocuments,
  3055. VSQUERYREMOVEDIRECTORYFLAGS[] rgFlags,
  3056. VSQUERYREMOVEDIRECTORYRESULTS[] pSummaryResult,
  3057. VSQUERYREMOVEDIRECTORYRESULTS[] rgResults)
  3058. {
  3059. return 0;
  3060. }
  3061. public int OnQueryRemoveFiles(IVsProject pProject, int cFiles, string[] rgpszMkDocuments,
  3062. VSQUERYREMOVEFILEFLAGS[] rgFlags,
  3063. VSQUERYREMOVEFILERESULTS[] pSummaryResult,
  3064. VSQUERYREMOVEFILERESULTS[] rgResults)
  3065. {
  3066. return 0;
  3067. }
  3068. public int OnQueryRenameDirectories(IVsProject pProject, int cDirs, string[] rgszMkOldNames,
  3069. string[] rgszMkNewNames, VSQUERYRENAMEDIRECTORYFLAGS[] rgFlags,
  3070. VSQUERYRENAMEDIRECTORYRESULTS[] pSummaryResult,
  3071. VSQUERYRENAMEDIRECTORYRESULTS[] rgResults)
  3072. {
  3073. return 0;
  3074. }
  3075. public int OnQueryRenameFiles(IVsProject ivsProject, int cFiles, string[] oldNames, string[] newNames,
  3076. VSQUERYRENAMEFILEFLAGS[] rgFlags, VSQUERYRENAMEFILERESULTS[] pSummaryResult,
  3077. VSQUERYRENAMEFILERESULTS[] rgResults)
  3078. {
  3079. for(int i = 0; i < oldNames.Length; ++i)
  3080. {
  3081. string oldName = oldNames[i];
  3082. string newName = newNames[i];
  3083. if(String.IsNullOrEmpty(oldName) || String.IsNullOrEmpty(newName))
  3084. {
  3085. continue;
  3086. }
  3087. if(!Util.isSliceFilename(oldName) )
  3088. {
  3089. continue;
  3090. }
  3091. ProjectItem item = Util.findItem(oldName);
  3092. if(item == null)
  3093. {
  3094. continue;
  3095. }
  3096. if(!Util.isProjectItemFile(item))
  3097. {
  3098. continue;
  3099. }
  3100. Project project = item.ContainingProject;
  3101. if(project == null)
  3102. {
  3103. continue;
  3104. }
  3105. try
  3106. {
  3107. if(Util.isCSharpProject(project))
  3108. {
  3109. String csPath = getCSharpGeneratedFileName(project, newName, "cs");
  3110. if(File.Exists(csPath) || Util.findItem(csPath, project.ProjectItems) != null)
  3111. {
  3112. MessageBox.Show("A file named '" + Path.GetFileName(csPath) +
  3113. "' already exists.\n" + oldName +
  3114. " could not be renamed to '" + item.Name + "'.",
  3115. "Ice Visual Studio Add-in",
  3116. MessageBoxButtons.OK,
  3117. MessageBoxIcon.Error,
  3118. MessageBoxDefaultButton.Button1,
  3119. (MessageBoxOptions)0);
  3120. return -1;
  3121. }
  3122. //
  3123. // Get rid of generated files, for the removed .ice file.
  3124. //
  3125. fileTracker().reap(project);
  3126. ProjectItem generatedItem = Util.findItem(getCSharpGeneratedFileName(project, item, "cs"),
  3127. project.ProjectItems);
  3128. if(generatedItem == null)
  3129. {
  3130. continue;
  3131. }
  3132. generatedItem.Delete();
  3133. }
  3134. else if(Util.isCppProject(project))
  3135. {
  3136. string cppPath = getCppGeneratedFileName(project, newName, "." + Util.getSourceExt(project));
  3137. string hPath = Path.ChangeExtension(cppPath, "." + Util.getHeaderExt(project));
  3138. if(File.Exists(cppPath) || Util.findItem(cppPath, project.ProjectItems) != null)
  3139. {
  3140. MessageBox.Show("A file named '" + Path.GetFileName(cppPath) +
  3141. "' already exists.\n" + "If you want to add '" +
  3142. Path.GetFileName(newName) + "' first remove " + " '" +
  3143. Path.GetFileName(cppPath) + "' and '" +
  3144. Path.GetFileName(hPath) + "' from your project.",
  3145. "Ice Visual Studio Add-in",
  3146. MessageBoxButtons.OK, MessageBoxIcon.Error,
  3147. MessageBoxDefaultButton.Button1, (MessageBoxOptions)0);
  3148. return -1;
  3149. }
  3150. if(File.Exists(hPath) || Util.findItem(hPath, project.ProjectItems) != null)
  3151. {
  3152. MessageBox.Show("A file named '" + Path.GetFileName(hPath) +
  3153. "' already exists.\n" + "If you want to add '" +
  3154. Path.GetFileName(newName) + "' first remove " +
  3155. " '" + Path.GetFileName(cppPath) + "' and '" +
  3156. Path.GetFileName(hPath) + "' from your project.",
  3157. "Ice Visual Studio Add-in",
  3158. MessageBoxButtons.OK, MessageBoxIcon.Error,
  3159. MessageBoxDefaultButton.Button1, (MessageBoxOptions)0);
  3160. return -1;
  3161. }
  3162. //
  3163. // Get rid of generated files, for the removed .ice file.
  3164. //
  3165. fileTracker().reap(project);
  3166. string cppGeneratedPath = getCppGeneratedFileName(project, oldName, Util.getSourceExt(project));
  3167. string hGeneratedPath = Path.ChangeExtension(cppGeneratedPath, Util.getHeaderExt(project));
  3168. ProjectItem generatedItem = Util.findItem(cppGeneratedPath, project.ProjectItems);
  3169. if(generatedItem != null)
  3170. {
  3171. generatedItem.Delete();
  3172. }
  3173. generatedItem = Util.findItem(hGeneratedPath, project.ProjectItems);
  3174. if(generatedItem != null)
  3175. {
  3176. generatedItem.Delete();
  3177. }
  3178. }
  3179. }
  3180. catch(Exception ex)
  3181. {
  3182. Util.write(null, Util.msgLevel.msgError, ex.ToString() + "\n");
  3183. Util.unexpectedExceptionWarning(ex);
  3184. throw;
  3185. }
  3186. }
  3187. return 0;
  3188. }
  3189. #endregion
  3190. private FileTracker fileTracker()
  3191. {
  3192. if(_fileTracker == null)
  3193. {
  3194. _fileTracker = new FileTracker();
  3195. }
  3196. return _fileTracker;
  3197. }
  3198. private DTE2 _applicationObject;
  3199. private AddIn _addInInstance;
  3200. private ext_ConnectMode _connectMode;
  3201. private SolutionEvents _solutionEvents;
  3202. private SelectionEvents _selectionEvents;
  3203. private BuildEvents _buildEvents;
  3204. private DocumentEvents _docEvents;
  3205. private ProjectItemsEvents _csProjectItemsEvents;
  3206. private VCProjectEngineEvents _vcProjectItemsEvents;
  3207. private ServiceProvider _serviceProvider;
  3208. private ErrorListProvider _errorListProvider;
  3209. private List<ErrorTask> _errors;
  3210. private int _errorCount;
  3211. private FileTracker _fileTracker;
  3212. private DependenciesMap _dependenciesMap;
  3213. private string _deletedFile;
  3214. private OutputWindowPane _output;
  3215. private CommandEvents _addNewItemEvent;
  3216. private CommandEvents _addExistingItemEvent;
  3217. private CommandEvents _editRemoveEvent;
  3218. private CommandEvents _excludeFromProjectEvent;
  3219. private CommandEvents _editDeleteEvent;
  3220. private CommandEvents _buildCancelEvent;
  3221. private CommandEvents _debugStartEvent;
  3222. private CommandEvents _debugStepIntoEvent;
  3223. private CommandEvents _debugStepIntoNewInstance;
  3224. private CommandEvents _debugStartWithoutDebuggingEvent;
  3225. private CommandEvents _debugStartNewInstance;
  3226. private List<String> _deleted = new List<String>();
  3227. private List<Project> _rebuildProjects;
  3228. private Command _iceConfigurationCmd;
  3229. private string _excludedItem = null;
  3230. //
  3231. // The first of several parallel builds sets it to true in the "buildBegin"
  3232. // event handler, to ensure the slice compiler is run only once, then it's reset
  3233. // to false when the build ends or is canceled.
  3234. //
  3235. private bool _sliceBuild = false;
  3236. //
  3237. // True if build is in process, false otherwise.
  3238. //
  3239. private bool _building = false;
  3240. //
  3241. // This contains the build scope of the last build command.
  3242. //
  3243. private vsBuildScope _buildScope = vsBuildScope.vsBuildScopeSolution;
  3244. //
  3245. // If build is in process and the build scope is "vsBuildScopeProject",
  3246. // this contains a reference to the project, otherwise it's null.
  3247. //
  3248. private Project _buildProject;
  3249. private uint _dwCookie;
  3250. private bool _opening = false;
  3251. private bool _opened = false; // True after solutionOpened has been executed.
  3252. public bool commandLine;
  3253. }
  3254. }