|
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.ComponentModel; |
4 | 4 | using System.Diagnostics; |
| 5 | +using System.IO; |
5 | 6 | using System.Runtime.CompilerServices; |
| 7 | +using System.Runtime.InteropServices; |
6 | 8 | using Microsoft.Azure.Kinect.BodyTracking; |
7 | 9 | using Microsoft.Azure.Kinect.Sensor; |
8 | 10 | using Microsoft.Extensions.Logging; |
|
11 | 13 | namespace OpenSense.Components.AzureKinect.BodyTracking { |
12 | 14 | public sealed class AzureKinectBodyTracker : INotifyPropertyChanged, IDisposable { |
13 | 15 |
|
| 16 | + private const string K4abtLibDir = "k4abt";//Set in csproj |
| 17 | + |
| 18 | + private const string K4abtDll = "k4abt.dll"; |
| 19 | + |
14 | 20 | #region Options |
15 | 21 |
|
16 | 22 | private SensorOrientation sensorOrientation; |
@@ -121,6 +127,7 @@ private void ProcessCalibration(Calibration calibration, Envelope envelope) { |
121 | 127 | GpuDeviceId = GpuDeviceId, |
122 | 128 | ModelPath = modelPath, |
123 | 129 | }; |
| 130 | + PreloadK4abtAndDependencies(); |
124 | 131 | /** NOTE: |
125 | 132 | * AzureKinectBodyTrackingCreateException does not contain any error detail. |
126 | 133 | * To know the detail, you need to look at its log. |
@@ -196,6 +203,37 @@ private void SetProperty<T>(ref T field, T value, [CallerMemberName] string? pro |
196 | 203 | } |
197 | 204 | #endregion |
198 | 205 |
|
| 206 | + #region P/Invoke |
| 207 | + |
| 208 | + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] |
| 209 | + private static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); |
| 210 | + |
| 211 | + public static void PreloadK4abtAndDependencies() { |
| 212 | + var baseDir = AppContext.BaseDirectory; |
| 213 | + if (File.Exists(Path.Combine(baseDir, K4abtDll))) { |
| 214 | + /* NOTE: |
| 215 | + * Since the dependencies of k4abt.dll are located in both the application base directory and the AzureKinectLibs directory (LOAD_LIBRARY_SEARCH_USER_DIRS), |
| 216 | + * we need to enable both locations in the DLL search path. |
| 217 | + * |
| 218 | + * However, Windows only supports enabling or disabling directories for DLL searches—it does not allow us to explicitly define the search order between them. |
| 219 | + * |
| 220 | + * This means that if k4abt.dll exists in the application base directory, its dependencies (ONNX DLLs) will be loaded from the base directory, even if we explicitly load k4abt.dll from AzureKinectLibs. |
| 221 | + * This behavior is counterintuitive, but observed. |
| 222 | + * |
| 223 | + * As a result, we ensure that k4abt.dll does not exist in the application base directory. |
| 224 | + */ |
| 225 | + throw new Exception($"k4abt.dll exists in application base directory. It shouldn't be there."); |
| 226 | + } |
| 227 | + var extraDllDir = Path.Combine(baseDir, K4abtLibDir); |
| 228 | + var k4abtPath = Path.Combine(extraDllDir, K4abtDll); |
| 229 | + var handle = LoadLibraryEx(k4abtPath, IntPtr.Zero, 0);//We have to load this k4abt.dll, otherwise there is no chance our application knows it is there. |
| 230 | + if (handle == IntPtr.Zero) { |
| 231 | + int error = Marshal.GetLastWin32Error(); |
| 232 | + throw new InvalidOperationException($"Failed to load k4abt.dll, error code: {error}"); |
| 233 | + } |
| 234 | + } |
| 235 | + #endregion |
| 236 | + |
199 | 237 | #region IDisposable |
200 | 238 | private bool disposed; |
201 | 239 |
|
|
0 commit comments