Compare commits
No commits in common. "d90ebb826f7849173f49e027852532d59c651611" and "e3321ff2793346241d0756005a9378c04a153b91" have entirely different histories.
d90ebb826f
...
e3321ff279
4 changed files with 12 additions and 100 deletions
12
TeamsISO.sln
12
TeamsISO.sln
|
|
@ -5,19 +5,19 @@ VisualStudioVersion = 17.0.31903.59
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{46E05E34-8A87-4986-87D3-FE0DE4E05F44}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine", "src/TeamsISO.Engine/TeamsISO.Engine.csproj", "{F0D24EAE-9225-4DC4-B3D2-6966077287A0}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine", "src\TeamsISO.Engine\TeamsISO.Engine.csproj", "{F0D24EAE-9225-4DC4-B3D2-6966077287A0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine.NdiInterop", "src/TeamsISO.Engine.NdiInterop/TeamsISO.Engine.NdiInterop.csproj", "{E737E54B-73DE-4F74-909C-1F0F5CF82AC6}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine.NdiInterop", "src\TeamsISO.Engine.NdiInterop\TeamsISO.Engine.NdiInterop.csproj", "{E737E54B-73DE-4F74-909C-1F0F5CF82AC6}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DBDF4A1D-4215-42D5-B456-2CE7159DF848}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine.Tests", "src/tests/TeamsISO.Engine.Tests/TeamsISO.Engine.Tests.csproj", "{F8DBD7AB-E160-4B75-88FC-BAECDD4D44E8}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine.Tests", "src\tests\TeamsISO.Engine.Tests\TeamsISO.Engine.Tests.csproj", "{F8DBD7AB-E160-4B75-88FC-BAECDD4D44E8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.App", "src/TeamsISO.App/TeamsISO.App.csproj", "{80DCE039-3BBC-4D3F-B44B-51F324591C29}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.App", "src\TeamsISO.App\TeamsISO.App.csproj", "{80DCE039-3BBC-4D3F-B44B-51F324591C29}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine.IntegrationTests", "src/tests/TeamsISO.Engine.IntegrationTests/TeamsISO.Engine.IntegrationTests.csproj", "{A85E331D-026E-4BDE-B89C-0CC4C95001CE}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Engine.IntegrationTests", "src\tests\TeamsISO.Engine.IntegrationTests\TeamsISO.Engine.IntegrationTests.csproj", "{A85E331D-026E-4BDE-B89C-0CC4C95001CE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Console", "src/TeamsISO.Console/TeamsISO.Console.csproj", "{C3254998-9428-4264-A8FB-EAC9E1F9F432}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeamsISO.Console", "src\TeamsISO.Console\TeamsISO.Console.csproj", "{C3254998-9428-4264-A8FB-EAC9E1F9F432}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
|
|||
|
|
@ -4,30 +4,13 @@ namespace TeamsISO.Engine.NdiInterop;
|
|||
|
||||
/// <summary>
|
||||
/// P/Invoke declarations for the NewTek/Vizrt NDI SDK 6 native library.
|
||||
/// On Windows the import target is <c>Processing.NDI.Lib.x64.dll</c>. Resolution of
|
||||
/// the DLL is handled by <see cref="NdiNativeLibraryResolver"/>, which loads it from
|
||||
/// the NDI Runtime installation directory exposed by the
|
||||
/// <c>NDI_RUNTIME_DIR_V<n></c> environment variables — the NDI installer sets
|
||||
/// these but does not always add the runtime directory to <c>PATH</c>, so a default
|
||||
/// loader-based resolution would fail with <c>0x8007007E</c> on otherwise correctly
|
||||
/// installed machines.
|
||||
/// On Windows the import target is <c>Processing.NDI.Lib.x64.dll</c>; the loader resolves it
|
||||
/// from the NDI Runtime installation path or from the application directory.
|
||||
/// </summary>
|
||||
internal static class NdiNative
|
||||
{
|
||||
private const string LibName = "Processing.NDI.Lib.x64";
|
||||
|
||||
/// <summary>
|
||||
/// Registers <see cref="NdiNativeLibraryResolver"/> with the runtime before any
|
||||
/// P/Invoke against <see cref="LibName"/> fires. The static constructor is
|
||||
/// guaranteed to run before the first access to any member of this type, which
|
||||
/// includes the very first <c>[DllImport]</c> call site, so the resolver is
|
||||
/// always in place when the loader needs it.
|
||||
/// </summary>
|
||||
static NdiNative()
|
||||
{
|
||||
NdiNativeLibraryResolver.Register();
|
||||
}
|
||||
|
||||
// ---- Lifecycle ----
|
||||
[DllImport(LibName, EntryPoint = "NDIlib_initialize", CallingConvention = CallingConvention.Cdecl)]
|
||||
[return: MarshalAs(UnmanagedType.U1)]
|
||||
|
|
|
|||
|
|
@ -1,66 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace TeamsISO.Engine.NdiInterop;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the NDI native library (<c>Processing.NDI.Lib.x64.dll</c>) from the
|
||||
/// NDI Runtime install directory exposed via <c>NDI_RUNTIME_DIR_V<n></c>
|
||||
/// environment variables.
|
||||
///
|
||||
/// The NDI installer creates these env vars but does not always add the runtime
|
||||
/// directory to <c>PATH</c>, so a default <c>[DllImport("Processing.NDI.Lib.x64")]</c>
|
||||
/// can fail with <c>0x8007007E</c> ("the specified module could not be found") on
|
||||
/// otherwise correctly installed machines. This resolver patches that gap by
|
||||
/// pre-loading the DLL from the install dir before the runtime falls back to its
|
||||
/// default search algorithm.
|
||||
///
|
||||
/// The resolver is registered from the static constructor of <see cref="NdiNative"/>,
|
||||
/// which guarantees it runs before the first P/Invoke on that type fires. On
|
||||
/// non-Windows the resolver short-circuits; the assembly's P/Invokes are gated by
|
||||
/// <c>[SupportedOSPlatform("windows")]</c> and won't fire there in any case.
|
||||
/// </summary>
|
||||
internal static class NdiNativeLibraryResolver
|
||||
{
|
||||
private const string NdiX64LibraryName = "Processing.NDI.Lib.x64";
|
||||
private const string NdiX64LibraryFile = "Processing.NDI.Lib.x64.dll";
|
||||
|
||||
/// <summary>
|
||||
/// NDI runtime install-dir environment variables, in preference order.
|
||||
/// V6 is what TeamsISO is built against; V5/V4 are listed as graceful fallbacks
|
||||
/// for installs that pre-date V6 — the runtime probe will still report a
|
||||
/// version mismatch, but at least the DLL will load and the engine can surface
|
||||
/// a clear alert instead of dying with DllNotFoundException.
|
||||
/// </summary>
|
||||
private static readonly string[] EnvVarFallbacks =
|
||||
{
|
||||
"NDI_RUNTIME_DIR_V6",
|
||||
"NDI_RUNTIME_DIR_V5",
|
||||
"NDI_RUNTIME_DIR_V4",
|
||||
};
|
||||
|
||||
internal static void Register()
|
||||
{
|
||||
NativeLibrary.SetDllImportResolver(typeof(NdiNativeLibraryResolver).Assembly, Resolve);
|
||||
}
|
||||
|
||||
private static IntPtr Resolve(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||
{
|
||||
if (libraryName != NdiX64LibraryName) return IntPtr.Zero;
|
||||
if (!OperatingSystem.IsWindows()) return IntPtr.Zero;
|
||||
|
||||
foreach (var envVar in EnvVarFallbacks)
|
||||
{
|
||||
var dir = Environment.GetEnvironmentVariable(envVar);
|
||||
if (string.IsNullOrEmpty(dir)) continue;
|
||||
var path = Path.Combine(dir, NdiX64LibraryFile);
|
||||
if (!File.Exists(path)) continue;
|
||||
if (NativeLibrary.TryLoad(path, out var handle))
|
||||
return handle;
|
||||
}
|
||||
|
||||
// Fall through to default loader (PATH, app dir, etc.) — preserves the
|
||||
// chance that someone added the NDI dir to PATH manually.
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,14 +12,9 @@ public static class NdiVersion
|
|||
public const string SdkFamily = "NDI 6";
|
||||
|
||||
/// <summary>
|
||||
/// Prefix of the runtime version banner we expect. The shipping NDI 6 runtime
|
||||
/// reports its version as a build banner of the form
|
||||
/// "NDI SDK WIN64 13:07:00 Jun 2 2025 6.2.0.3"
|
||||
/// where the architecture token ("WIN64" / "WIN32") is stable across patch
|
||||
/// releases and confirms we loaded the binary the engine P/Invokes against
|
||||
/// (Processing.NDI.Lib.x64.dll). The trailing four-part token is the SDK's
|
||||
/// numeric version. The probe checks this prefix; a stricter probe could
|
||||
/// additionally enforce the leading "6." in the trailing version token.
|
||||
/// Prefix of the runtime version string we expect (NDI runtime reports e.g.
|
||||
/// "NDI SDK for Windows v6.0.1.0"). Any major change of the leading "v6" is treated
|
||||
/// as a mismatch.
|
||||
/// </summary>
|
||||
public const string ExpectedRuntimeVersionPrefix = "NDI SDK WIN64";
|
||||
public const string ExpectedRuntimeVersionPrefix = "NDI SDK for Windows v6";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue