public static void RunWindows() { string arch; // Detect the process architecture switch (RuntimeInformation.ProcessArchitecture) { case Architecture.X86: // Workaround for a detection issue. If x86 is detected, but IntPtr is 8 bytes long, we're on x64 // See https://github.com/dotnet/corefx/issues/25267 if (IntPtr.Size == 8) { arch = "x64"; } else { arch = "x86"; } break; case Architecture.X64: arch = "x64"; break; default: throw new PlatformNotSupportedException("Only x86 and x64 are supported at the moment"); } Console.WriteLine(arch); // Load the correct library var projectDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)))); var handle = WindowsInterop.LoadLibrary(Path.Combine(projectDir, "nativeLibrary", "build", arch, "nativeLibrary.dll")); if (handle == IntPtr.Zero) { Console.Error.WriteLine("Failed to load native library"); throw new Win32Exception(Marshal.GetLastWin32Error()); } try { // Locate the "triggerCallback" function. This function just calls the callback with some parameters. var procAddress = WindowsInterop.GetProcAddress(handle, "triggerCallback"); if (procAddress == IntPtr.Zero) { Console.Error.WriteLine("Failed to locate the triggerCallback function."); throw new Win32Exception(Marshal.GetLastWin32Error()); } var triggerCallback = Marshal.GetDelegateForFunctionPointer <NativeLibrary.TriggerCallback>(procAddress); triggerCallback(WindowsCallback); } finally { WindowsInterop.FreeLibrary(handle); } }
public static void WindowsCallback(string format, IntPtr args) { // This implementation is pretty straightforward. The IntPtr can be passed to the functions and can be reused. var byteLength = WindowsInterop._vscprintf(format, args) + 1; var utf8Buffer = Marshal.AllocHGlobal(byteLength); try { WindowsInterop.vsprintf(utf8Buffer, format, args); Console.WriteLine(Utf8ToString(utf8Buffer)); } finally { Marshal.FreeHGlobal(utf8Buffer); } }