bovender framework
C# framework that implements MVVM and more
DllManager.cs
1 /* DllManager.cs
2  * part of Daniel's XL Toolbox NG
3  *
4  * Copyright 2014-2018 Daniel Kraus
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 using System;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Text;
22 using System.IO;
23 using System.Runtime.InteropServices;
24 using System.ComponentModel;
25 
26 namespace Bovender.Unmanaged
27 {
31  public class DllManager : IDisposable
32  {
33  #region Public static property
34 
35  public static string AlternativeDir { get; set; }
36 
37  #endregion
38 
39  #region Public static methods
40 
48  public static bool DllExists(string dllFileName)
49  {
50  Logger.Info("DllExists: {0}", dllFileName);
51  return !String.IsNullOrEmpty(LocateDll(dllFileName));
52  }
53 
61  public static string LocateDll(string dllName)
62  {
63  Logger.Info("LocateDll: {0}", dllName);
64  string dllPath = CompletePath(ApplicationDir(), dllName);
65  bool found = File.Exists(dllPath);
66  if (!found && !String.IsNullOrWhiteSpace(AlternativeDir))
67  {
68  Logger.Info("LocateDll: Looking in alternative directory '{0}'", AlternativeDir);
69  dllPath = CompletePath(AlternativeDir, dllName);
70  found = File.Exists(dllPath);
71  }
72  if (found)
73  {
74  Logger.Info("LocateDll: Found");
75  return dllPath;
76  }
77  else
78  {
79  Logger.Warn("LocateDll: {0} not found", dllName);
80  return String.Empty;
81  }
82  }
83 
84  #endregion
85 
86  #region Private static methods
87 
98  private static string CompletePath(string baseDir, string fileName)
99  {
100  if (!Path.HasExtension(fileName))
101  {
102  fileName += ".dll";
103  };
104  string s = Path.Combine(baseDir,
105  "lib",
106  Environment.Is64BitProcess ? "x64" : "Win32",
107  fileName);
108  Logger.Info("CompletePath: '{0}'", s);
109  return s;
110  }
111 
112  private static string ApplicationDir()
113  {
114  return AppDomain.CurrentDomain.BaseDirectory;
115  }
116 
117  #endregion
118 
119  #region Public methods
120 
134  public void LoadDll(string dllName)
135  {
136  LoadDll(dllName, String.Empty);
137  }
138 
154  // TODO: Use two expected hashes, one for Win32, one for x64
155  public void LoadDll(string dllName, string expectedSha256Hash)
156  {
157  if (_dlls.Contains(dllName))
158  {
159  Logger.Info("LoadDll: '{0}' already registered in this instance", dllName);
160  }
161  else
162  {
163  Logger.Info("LoadDll: '{0}'", dllName);
164 
165  string dllPath = LocateDll(dllName);
166  if (String.IsNullOrEmpty(dllPath))
167  {
168  Logger.Fatal("LoadDll: Unable to locate DLL!");
169  throw new DllNotFoundException(String.Format("Unable to locate DLL file"));
170  }
171 
172  DllFile dllFile;
173  if (_globalDlls.TryGetValue(dllName, out dllFile))
174  {
175  Logger.Info("LoadDll: Already registered");
176  }
177  else
178  {
179  Logger.Info("LoadDll: Registering new DLL");
180  dllFile = new DllFile(dllPath, expectedSha256Hash);
181  _globalDlls.Add(dllName, dllFile);
182  }
183  dllFile.Load();
184  _dlls.Add(dllName);
185  }
186  }
187 
192  public void UnloadDll(string dllName)
193  {
194  if (_dlls.Contains(dllName))
195  {
196  DllFile dllFile;
197  if (_globalDlls.TryGetValue(dllName, out dllFile))
198  {
199  Logger.Info("UnloadDll: Unloading '{0}'", dllName);
200  // Decrease the usage counter
201  dllFile.Unload();
202  _globalDlls.Remove(dllName);
203  }
204  else
205  {
206  Logger.Warn("UnloadDll: Attempting to unload '{0}' which is not globally registered?!", dllName);
207  }
208  _dlls.Remove(dllName);
209  }
210  else
211  {
212  Logger.Warn("UnloadDll: '{0}' not known to this instance");
213  }
214  }
215 
216  #endregion
217 
218  #region Constructor
219 
220  public DllManager()
221  {
222  _dlls = new List<string>();
223  }
224 
225  public DllManager(params string[] loadDlls)
226  : this()
227  {
228  Logger.Info("DllManager: Constructor invoked with loadDlls array");
229  foreach (string dll in loadDlls)
230  {
231  LoadDll(dll);
232  }
233  Logger.Info("DllManager: All loaded");
234  }
235 
236  #endregion
237 
238  #region Destructing and disposing
239 
240  ~DllManager()
241  {
242  Dispose(false);
243  }
244 
245  public void Dispose()
246  {
247  Dispose(true);
248  GC.SuppressFinalize(this);
249  }
250 
251  protected virtual void Dispose(bool calledFromDispose)
252  {
253  if (!_disposed)
254  {
255  _disposed = true;
256  if (calledFromDispose)
257  {
258  // May use managed resources here
259  Logger.Info("Dispose: Unloading {0} DLL(s).", _dlls.Count);
260  foreach (string dll in _dlls)
261  {
262  DllFile dllFile;
263  if (_globalDlls.TryGetValue(dll, out dllFile))
264  {
265  dllFile.Unload();
266  }
267  }
268  }
269  }
270  }
271 
272  #endregion
273 
274  #region Private fields
275 
276  private List<string> _dlls;
277  private bool _disposed;
278 
279  #endregion
280 
281  #region Private static fields
282 
286  private static readonly Dictionary<string, DllFile> _globalDlls = new Dictionary<string, DllFile>();
287 
288  #endregion
289 
290  #region Private constant
291 
292  private const string LIBDIR = "lib";
293 
294  #endregion
295 
296  #region Class logger
297 
298  private static NLog.Logger Logger { get { return _logger.Value; } }
299 
300  private static readonly Lazy<NLog.Logger> _logger = new Lazy<NLog.Logger>(() => NLog.LogManager.GetCurrentClassLogger());
301 
302  #endregion
303  }
304 }
static bool DllExists(string dllFileName)
Checks whether a DLL exists in the application directory or in the custom AlternativeDir.
Definition: DllManager.cs:48
Manages unmanaged DLLs.
Definition: DllManager.cs:31
static string LocateDll(string dllName)
Attempts to locate a DLL file in the canonical location (subdirectory of the application directory) o...
Definition: DllManager.cs:61
void LoadDll(string dllName)
Loads the given DLL from the appropriate subdirectory, depending on the current bitness.
Definition: DllManager.cs:134
void UnloadDll(string dllName)
Unloads a previously loaded DLL.
Definition: DllManager.cs:192
void LoadDll(string dllName, string expectedSha256Hash)
Loads the given DLL from the appropriate subdirectory if its Sha1 hash matches the provided hash...
Definition: DllManager.cs:155
Represents a single DLL file.
Definition: DllFile.cs:30