/// <summary> /// Notifies all of the listeners that a build operation is in progress. /// </summary> /// <returns>true if the build should continue; false if one or more of the listeners requested /// that the build should be canceled.</returns> public bool OnTick() { bool continueBuilding = true; // Let all of our listeners know that the build has started. Tracer.WriteLineVerbose(classType, "OnTick", "Notifying all of our listeners that the build is in progress."); // There are some cases where the collection is changed while we're iterating it. // To be safe, we'll create a copy of the collection and iterate over that. // We just want a shallow copy, though, and not a deep (Clone) copy. ArrayList clone = new ArrayList(this.Values); foreach (IVsBuildStatusCallback eventItem in clone) { try { int continueFlag = Convert.ToInt32(continueBuilding); eventItem.Tick(ref continueFlag); if (continueFlag == 0) { continueBuilding = false; } } catch (Exception e) { Tracer.WriteLine(classType, "OnTick", Tracer.Level.Warning, "There was an exception in one of the listener's event handling code: {0}", e.ToString()); } } return(continueBuilding); }
/// <summary> /// Notifies all of our event listeners that an item in the hierarchy has changed. /// </summary> /// <param name="node">The <see cref="Node"/> that has changed.</param> /// <param name="propertyId">The property that has changed.</param> public void OnPropertyChanged(Node node, __VSHPROPID propertyId) { Tracer.VerifyNonNullArgument(node, "node"); object newValue; node.GetProperty(propertyId, out newValue); // There are some cases where the collection is changed while we're iterating it. // To be safe, we'll create a copy of the collection and iterate over that. // We just want a shallow copy, though, and not a deep (Clone) copy. ArrayList clone = new ArrayList(this.Values); for (int i = 0; i < clone.Count; i++) { IVsHierarchyEvents eventItem = (IVsHierarchyEvents)clone[i]; Tracer.WriteLineVerbose(classType, "OnPropertyChanged", "Notifying event listener {0} that '{1}' has changed its {2} property to '{3}'.", this.CookieOf(i), node.Caption, propertyId, newValue); try { eventItem.OnPropertyChanged(node.HierarchyId, (int)propertyId, 0); } catch (Exception e) { Tracer.WriteLineWarning(classType, "OnPropertyChanged", "There was an exception in the event listener {0} event handling code: {1}", this.CookieOf(i), e.ToString()); } } }
/// <summary> /// Resumes file change notifications to the environment for the wrapped file. /// </summary> public void Resume() { if (!this.suspended) { return; } // Get the environment's change notifier. IVsFileChangeEx changeNotifier = Package.Instance.Context.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx; Tracer.WriteLineIf(classType, "Resume", Tracer.Level.Warning, changeNotifier == null, "Could not get an instance of the IVsChangeEx interface."); if (changeNotifier != null) { // Tell the environment to resume sending change notifications for the file. int hr = changeNotifier.IgnoreFile(0, this.FilePath, ResumeNotification); Tracer.WriteLineIf(classType, "Resume", Tracer.Level.Warning, NativeMethods.Failed(hr), "Could not tell the environment to resume file change notifications to '{0}': Hr=0x{1:x}", this.FilePath, hr); } // Tell the environment to resume sending change notifications to editors. if (this.docDataFileChangeControl != null) { int hr = this.docDataFileChangeControl.IgnoreFileChanges(ResumeNotification); Tracer.WriteLineIf(classType, "Resume", Tracer.Level.Warning, NativeMethods.Failed(hr), "Could not tell the environment to resume file change notifications to editors of file '{0}': Hr=0x{1:x}", this.FilePath, hr); this.docDataFileChangeControl = null; } // At this point we can consider ourself resumed. this.suspended = false; Tracer.WriteLineVerbose(classType, "Resume", "Resumed file change notifications for '{0}'.", this.FilePath); }
/// <summary> /// Gets the service object of the specified type. /// </summary> /// <param name="serviceType">An object that specifies the type of service object to get.</param> /// <returns> /// <para>A service object of type <paramref name="serviceType"/>.</para> /// <para>-or-</para> /// <para><see langword="null"/> if there is no service object of type /// <paramref name="serviceType"/>.</para> /// </returns> public object GetService(Type serviceType) { Tracer.VerifyNonNullArgument(serviceType, "serviceType"); Tracer.WriteLineVerbose(classType, "GetService", "ServiceType = {0}", serviceType.FullName); // Check for the special services that we provide. if (serviceType == typeof(IServiceContainer) || serviceType == Instance.GetType()) { return(this); } object value = null; // Check our proferred services list to see if we can return this service. if (this.services != null) { value = this.services[serviceType]; if (value is ProfferedService) { value = ((ProfferedService)value).Instance; } // If we have a callback then we have to attempt to create the service // by calling the callback method. if (value is ServiceCreatorCallback) { // In case the callback method tries to recursively call back into // us, we'll just null out the entry for this service now. That // way this method will just fail instead of allowing for a stack // overflow exception. this.services[serviceType] = null; // Let the callback create the service. Tracer.WriteLineVerbose(classType, "GetService", "Creating the {0} service via a callback.", serviceType.FullName); value = ((ServiceCreatorCallback)value)(this, serviceType); // Verify that the callback gave us a valid service. if (value != null && !value.GetType().IsCOMObject&& !serviceType.IsAssignableFrom(value.GetType())) { // Well, the callback was naughty and didn't give us what we wanted, but // let's not punish our caller by raising an exception. We'll just fail // by nulling the value. Tracer.Fail("The service creator callback returned the object '{0}' that doesn't implement the requested type '{1}'", value.GetType().FullName, serviceType.FullName); value = null; } // Set the created service in our proferred service list. this.services[serviceType] = value; } } // Let our parent provider handle the rest of the types. if (value == null && this.Context.ServiceProvider != null) { value = this.Context.ServiceProvider.GetService(serviceType); } return(value); }
/// <summary> /// Gets the service object of the specified type. /// </summary> /// <param name="serviceType">An object that specifies the type of service object to get.</param> /// <returns> /// A service object of type <paramref name="serviceType"/>, or <see langword="null"/> /// if there is no service object of type <paramref name="serviceType"/>. /// </returns> public object GetService(Type serviceType) { Tracer.VerifyNonNullArgument(serviceType, "serviceType"); Tracer.WriteLineVerbose(classType, "GetService", "ServiceType = {0}", serviceType.FullName); object service = this.GetService(serviceType.GUID); return(service); }
/// <summary> /// Acts as the factory method for any services exposed through an implementation of /// <see cref="IOleServiceProvider"/>. /// </summary> /// <param name="sid">Unique identifier of the service (an SID).</param> /// <param name="iid">Unique identifier of the interface the caller wishes to receive for the service.</param> /// <param name="ppvObj"> /// Address of the caller-allocated variable to receive the interface pointer of the /// service on successful return from this function. The caller becomes responsible /// for calling <b>Release</b> through this interface pointer when the service is no /// longer needed. /// </param> /// <returns> /// Returns one of the following values: /// <list type="table"> /// <item> /// <term>S_OK</term> /// <description>The service was successfully created or retrieved. The caller is /// responsible for calling ((IUnknown *)*ppv)->Release();.</description> /// </item> /// <item> /// <term>E_OUTOFMEMORY</term> /// <description>There is insufficient memory to create the service.</description> /// </item> /// <item> /// <term>E_UNEXPECTED</term> /// <description>An unknown error occurred.</description> /// </item> /// <item> /// <term>E_NOINTERFACE</term> /// <description>The service exists, but the interface requested does not exist /// on that service.</description> /// </item> /// </list> /// </returns> int IOleServiceProvider.QueryService(ref Guid sid, ref Guid iid, out IntPtr ppvObj) { Tracer.WriteLineVerbose(classType, "IOleServiceProvider.QueryService", "Querying for service {0}", sid.ToString("B")); ppvObj = IntPtr.Zero; int hr = NativeMethods.S_OK; object service = null; // See if we can find the service in our proffered services list. if (this.services != null) { foreach (Type serviceType in this.services.Keys) { if (serviceType.GUID == sid) { service = GetService(serviceType); break; } } } if (service == null) { Tracer.WriteLineVerbose(classType, "IOleServiceProvider.QueryService", "Could not find service {0}", sid.ToString("B")); return(NativeMethods.E_NOINTERFACE); } // If the caller requested an IID other than IUnknown, then we have to // query for that interface. Otherwise, we can just return the IUnknown. if (iid == NativeMethods.IID_IUnknown) { ppvObj = Marshal.GetIUnknownForObject(service); } else { IntPtr pUnk = Marshal.GetIUnknownForObject(service); hr = Marshal.QueryInterface(pUnk, ref iid, out ppvObj); Marshal.Release(pUnk); } return(hr); }
/// <summary> /// Suspends any file change notifications to the environment for the wrapped file in /// preparation for a multi-stage file operation such as a rename. /// </summary> public void Suspend() { // We only want to suspend once. if (this.suspended) { return; } // Get the environment's change notifier. IVsFileChangeEx changeNotifier = Package.Instance.Context.GetService(typeof(SVsFileChangeEx)) as IVsFileChangeEx; if (changeNotifier == null) { Tracer.WriteLineWarning(classType, "Suspend", "Could not get an instance of the IVsChangeEx interface."); return; } // Tell the environment to stop sending change notifications for the file. int hr = changeNotifier.IgnoreFile(0, this.FilePath, IgnoreChanges); Tracer.WriteLineIf(classType, "Suspend", Tracer.Level.Warning, NativeMethods.Failed(hr), "Could not tell the environment to ignore file changes to '{0}': Hr=0x{1:x}", this.FilePath, hr); NativeMethods.ThrowOnFailure(hr); // Get the IVsDocDataFileChangeControl interface from the DocumentData. We need this // to suspend file change notifications to all editors. DocumentInfo docInfo = Package.Instance.Context.RunningDocumentTable.FindByPath(this.FilePath); if (docInfo != null) { this.docDataFileChangeControl = docInfo.DocumentData as IVsDocDataFileChangeControl; if (this.docDataFileChangeControl != null) { hr = this.docDataFileChangeControl.IgnoreFileChanges(IgnoreChanges); NativeMethods.ThrowOnFailure(hr); } } // At this point we can consider ourself suspended. this.suspended = true; Tracer.WriteLineVerbose(classType, "Suspend", "Suspended file change notifications for '{0}'.", this.FilePath); }
/// <summary> /// Starts the specified build operation on the project for the currently selected project configuration. /// </summary> /// <param name="operation">The operation to perform.</param> public void StartBuild(BuildOperation operation) { Tracer.VerifyEnumArgument((int)operation, "operation", typeof(BuildOperation)); // We have to verify that the environment is not busy right now if (Package.Instance.Context.IsSolutionBuilding) { Tracer.WriteLineVerbose(classType, "StartBuild", "The build manager is busy right now."); return; } // Get the build manager from VS IVsSolutionBuildManager solutionBuildMgr = this.ServiceProvider.GetServiceOrThrow(typeof(SVsSolutionBuildManager), typeof(IVsSolutionBuildManager), classType, "StartBuild") as IVsSolutionBuildManager; // Convert the enum to one of the VS flags VSSOLNBUILDUPDATEFLAGS flags = VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_NONE; switch (operation) { case BuildOperation.Clean: flags |= VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_CLEAN; break; case BuildOperation.Build: flags |= VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD; break; case BuildOperation.Rebuild: flags |= VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_CLEAN | VSSOLNBUILDUPDATEFLAGS.SBF_OPERATION_BUILD; break; default: Tracer.Fail("Unknown BuildOperation '{0}'", operation.ToString()); return; } NativeMethods.ThrowOnFailure(solutionBuildMgr.StartSimpleUpdateProjectConfiguration((IVsHierarchy)this, null, null, (uint)flags, 0, 0)); }
int IVsCfgProvider2.GetCfgProviderProperty(int propid, out object pvar) { pvar = null; __VSCFGPROPID vsPropId = (__VSCFGPROPID)propid; switch (vsPropId) { case __VSCFGPROPID.VSCFGPROPID_SupportsCfgAdd: case __VSCFGPROPID.VSCFGPROPID_SupportsCfgDelete: case __VSCFGPROPID.VSCFGPROPID_SupportsCfgRename: pvar = true; break; case __VSCFGPROPID.VSCFGPROPID_SupportsPlatformAdd: case __VSCFGPROPID.VSCFGPROPID_SupportsPlatformDelete: pvar = false; break; } Tracer.WriteLineVerbose(classType, "IVsCfgProvider2.GetCfgProviderProperty", "Requested property '{0}' is {1}.", vsPropId, pvar); return NativeMethods.S_OK; }
/// <summary> /// Called right after the value is removed from the collection. /// </summary> /// <param name="index">The index of the item removed from the collection.</param> /// <param name="value">The value just removed from the collection.</param> protected virtual void OnRemoveComplete(int index, object value) { Tracer.WriteLineVerbose(classType, "OnRemoveComplete", "Removed '{0}' from the collection.", value.ToString()); }