OLD | NEW |
| (Empty) |
1 /// Copyright (c) Microsoft Corporation. All rights reserved. | |
2 | |
3 using System; | |
4 using System.Collections.Generic; | |
5 using System.Runtime.InteropServices; | |
6 using Microsoft.VisualStudio; | |
7 using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider; | |
8 | |
9 namespace Microsoft.VisualStudio.Project | |
10 { | |
11 public class OleServiceProvider : IOleServiceProvider, IDisposable | |
12 { | |
13 #region Public Types | |
14 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Desi
gn", "CA1034:NestedTypesShouldNotBeVisible")] | |
15 public delegate object ServiceCreatorCallback(Type serviceType); | |
16 #endregion | |
17 | |
18 #region Private Types | |
19 private class ServiceData : IDisposable | |
20 { | |
21 private Type serviceType; | |
22 private object instance; | |
23 private ServiceCreatorCallback creator; | |
24 private bool shouldDispose; | |
25 public ServiceData(Type serviceType, object instance, Se
rviceCreatorCallback callback, bool shouldDispose) | |
26 { | |
27 if(null == serviceType) | |
28 { | |
29 throw new ArgumentNullException("service
Type"); | |
30 } | |
31 | |
32 if((null == instance) && (null == callback)) | |
33 { | |
34 throw new ArgumentNullException("instanc
e"); | |
35 } | |
36 | |
37 this.serviceType = serviceType; | |
38 this.instance = instance; | |
39 this.creator = callback; | |
40 this.shouldDispose = shouldDispose; | |
41 } | |
42 | |
43 public object ServiceInstance | |
44 { | |
45 get | |
46 { | |
47 if(null == instance) | |
48 { | |
49 instance = creator(serviceType); | |
50 } | |
51 return instance; | |
52 } | |
53 } | |
54 | |
55 public Guid Guid | |
56 { | |
57 get { return serviceType.GUID; } | |
58 } | |
59 | |
60 public void Dispose() | |
61 { | |
62 if((shouldDispose) && (null != instance)) | |
63 { | |
64 IDisposable disp = instance as IDisposab
le; | |
65 if(null != disp) | |
66 { | |
67 disp.Dispose(); | |
68 } | |
69 instance = null; | |
70 } | |
71 creator = null; | |
72 GC.SuppressFinalize(this); | |
73 } | |
74 } | |
75 #endregion | |
76 | |
77 #region fields | |
78 | |
79 private Dictionary<Guid, ServiceData> services = new Dictionary<
Guid, ServiceData>(); | |
80 private bool isDisposed; | |
81 /// <summary> | |
82 /// Defines an object that will be a mutex for this object for s
ynchronizing thread calls. | |
83 /// </summary> | |
84 private static volatile object Mutex = new object(); | |
85 #endregion | |
86 | |
87 #region ctors | |
88 public OleServiceProvider() | |
89 { | |
90 } | |
91 #endregion | |
92 | |
93 #region IOleServiceProvider Members | |
94 | |
95 public int QueryService(ref Guid guidService, ref Guid riid, out
IntPtr ppvObject) | |
96 { | |
97 ppvObject = (IntPtr)0; | |
98 int hr = VSConstants.S_OK; | |
99 | |
100 ServiceData serviceInstance = null; | |
101 | |
102 if(services != null && services.ContainsKey(guidService)
) | |
103 { | |
104 serviceInstance = services[guidService]; | |
105 } | |
106 | |
107 if(serviceInstance == null) | |
108 { | |
109 return VSConstants.E_NOINTERFACE; | |
110 } | |
111 | |
112 // Now check to see if the user asked for an IID other t
han | |
113 // IUnknown. If so, we must do another QI. | |
114 // | |
115 if(riid.Equals(NativeMethods.IID_IUnknown)) | |
116 { | |
117 ppvObject = Marshal.GetIUnknownForObject(service
Instance.ServiceInstance); | |
118 } | |
119 else | |
120 { | |
121 IntPtr pUnk = IntPtr.Zero; | |
122 try | |
123 { | |
124 pUnk = Marshal.GetIUnknownForObject(serv
iceInstance.ServiceInstance); | |
125 hr = Marshal.QueryInterface(pUnk, ref ri
id, out ppvObject); | |
126 } | |
127 finally | |
128 { | |
129 if(pUnk != IntPtr.Zero) | |
130 { | |
131 Marshal.Release(pUnk); | |
132 } | |
133 } | |
134 } | |
135 | |
136 return hr; | |
137 } | |
138 | |
139 #endregion | |
140 | |
141 #region Dispose | |
142 | |
143 /// <summary> | |
144 /// The IDispose interface Dispose method for disposing the obje
ct determinastically. | |
145 /// </summary> | |
146 public void Dispose() | |
147 { | |
148 Dispose(true); | |
149 GC.SuppressFinalize(this); | |
150 } | |
151 | |
152 #endregion | |
153 | |
154 /// <summary> | |
155 /// Adds the given service to the service container. | |
156 /// </summary> | |
157 /// <param name="serviceType">The type of the service to add.</p
aram> | |
158 /// <param name="serviceInstance">An instance of the service.</p
aram> | |
159 /// <param name="shouldDisposeServiceInstance">true if the Dipos
e of the service provider is allowed to dispose the sevice instance.</param> | |
160 public void AddService(Type serviceType, object serviceInstance,
bool shouldDisposeServiceInstance) | |
161 { | |
162 // Create the description of this service. Note that we
don't do any validation | |
163 // of the parameter here because the constructor of Serv
iceData will do it for us. | |
164 ServiceData service = new ServiceData(serviceType, servi
ceInstance, null, shouldDisposeServiceInstance); | |
165 | |
166 // Now add the service desctription to the dictionary. | |
167 AddService(service); | |
168 } | |
169 | |
170 public void AddService(Type serviceType, ServiceCreatorCallback
callback, bool shouldDisposeServiceInstance) | |
171 { | |
172 // Create the description of this service. Note that we
don't do any validation | |
173 // of the parameter here because the constructor of Serv
iceData will do it for us. | |
174 ServiceData service = new ServiceData(serviceType, null,
callback, shouldDisposeServiceInstance); | |
175 | |
176 // Now add the service desctription to the dictionary. | |
177 AddService(service); | |
178 } | |
179 | |
180 private void AddService(ServiceData data) | |
181 { | |
182 // Make sure that the collection of services is created. | |
183 if(null == services) | |
184 { | |
185 services = new Dictionary<Guid, ServiceData>(); | |
186 } | |
187 | |
188 // Disallow the addition of duplicate services. | |
189 if(services.ContainsKey(data.Guid)) | |
190 { | |
191 throw new InvalidOperationException(); | |
192 } | |
193 | |
194 services.Add(data.Guid, data); | |
195 } | |
196 | |
197 /// <devdoc> | |
198 /// Removes the given service type from the service container. | |
199 /// </devdoc> | |
200 public void RemoveService(Type serviceType) | |
201 { | |
202 if(serviceType == null) | |
203 { | |
204 throw new ArgumentNullException("serviceType"); | |
205 } | |
206 | |
207 if(services.ContainsKey(serviceType.GUID)) | |
208 { | |
209 services.Remove(serviceType.GUID); | |
210 } | |
211 } | |
212 | |
213 #region helper methods | |
214 /// <summary> | |
215 /// The method that does the cleanup. | |
216 /// </summary> | |
217 /// <param name="disposing"></param> | |
218 protected virtual void Dispose(bool disposing) | |
219 { | |
220 // Everybody can go here. | |
221 if(!this.isDisposed) | |
222 { | |
223 // Synchronize calls to the Dispose simultenious
ly. | |
224 lock(Mutex) | |
225 { | |
226 if(disposing) | |
227 { | |
228 // Remove all our services | |
229 if(services != null) | |
230 { | |
231 foreach(ServiceData data
in services.Values) | |
232 { | |
233 data.Dispose(); | |
234 } | |
235 services.Clear(); | |
236 services = null; | |
237 } | |
238 } | |
239 | |
240 this.isDisposed = true; | |
241 } | |
242 } | |
243 } | |
244 #endregion | |
245 | |
246 } | |
247 } | |
OLD | NEW |