mono / SkiaSharp

SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render images.
MIT License
4.51k stars 538 forks source link

[QUESTION] How to correctly package SkiaSharp for Installer on Windows VS #2463

Open erebuswolf opened 1 year ago

erebuswolf commented 1 year ago

I have a WPF app that I added a SkiaSharp control to for high performance drawing. It works great. Runs fine in Visual Studio. It runs fine when I build and open the exe in the build output folder. But when I package an installer and try running the installed application, I get this error:

Unhandled Exception: System.TypeInitializationException: The type initializer for 'SkiaSharp.SKAbstractManagedStream' threw an exception. ---> System.DllNotFoundException: Unable to load library 'libSkiaSharp'.
   at SkiaSharp.LibraryLoader.LoadLocalLibrary[T](String libraryName)
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at SkiaSharp.SkiaApi.sk_managedstream_set_procs(SKManagedStreamDelegates procs)
   at SkiaSharp.SKAbstractManagedStream..cctor()
   --- End of inner exception stack trace ---
   at SkiaSharp.SKAbstractManagedStream..ctor(Boolean owns)
   at SkiaSharp.SKManagedStream..ctor(Stream managedStream, Boolean disposeManagedStream)
   at SkiaSharp.SKCodec.WrapManagedStream(Stream stream)
   at SkiaSharp.SKBitmap.Decode(Stream stream)
   at LabMonsterToolkit.SKImageStore.LoadResource(String key, String uri)
   at LabMonsterToolkit.SKImageStore.LoadResources()
   at LabMonsterToolkit.SKImageStore..ctor()
   at LabMonsterToolkit.SKImageStore.GetImageStoreSingle()
   at LabMonsterToolkit.TrainingWindow..ctor(ControllerInterface controllerInterface)
   at LabMonsterToolkit.MainWindow.OpenTrainer(Object sender, RoutedEventArgs e)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Button.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
   at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
   at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at LabMonsterToolkit.App.Main()

I've been searching trying to determine the source of the issue. I installed Skia vis the NuGet installer for the project. The following dlls are included as dependencies in the installer:

I can see the dlls are in the application directory for the installed application.

The dlls have the following attributes for the installer: DLL config

Any help is appreciated. I put a lot of work rewriting my applicaiton to use SkiaSharp and it works great. Hitting this roadblock is very frustrating.

Edit: When building the installer I found I have these error messages: WARNING: Unable to find dependency 'GLIB-SHARP' (Signature='35E10195DAB3C99F' Version='2.12.0.0') of assembly 'SkiaSharp.Views.Gtk.dll' WARNING: Unable to find dependency 'GTK-SHARP' (Signature='35E10195DAB3C99F' Version='2.12.0.0') of assembly 'SkiaSharp.Views.Gtk.dll' WARNING: Unable to find dependency 'GDK-SHARP' (Signature='35E10195DAB3C99F' Version='2.12.0.0') of assembly 'SkiaSharp.Views.Gtk.dll'

Looking into them further.

erebuswolf commented 1 year ago

After a good deal of trial and error I copied libSkiaSharp.dll and libSkiaSharp.dylib from my build output directory to my installed application folder and it was able to load the DLL for SkiaSharp. I am trying to figure out how to include those files implicitly through assembly dependencies, but I can't figure it out currently.

erebuswolf commented 1 year ago

Right now I just explicitly add the files to the installer "application folder" from the release bin directory. This feels like a really bad solution as it will be pulling from release even if I want to make a debug build. If there is a better cleaner way to do this please let me know.

ojb500 commented 1 year ago

I would guess your installer is missing the contents of the runtimes directory which is where the platform-specific libSkiaSharp.dll can be found?

On Thu, 18 May 2023 at 00:23, Jesse Fish @.***> wrote:

I have a WPF app that I added a SkiaSharp control to for high performance drawing. It works great. Runs fine in Visual Studio. It runs fine when I build and open the exe in the build output folder. But when I package an installer and try running the installed application, I get this error:

Unhandled Exception: System.TypeInitializationException: The type initializer for 'SkiaSharp.SKAbstractManagedStream' threw an exception. ---> System.DllNotFoundException: Unable to load library 'libSkiaSharp'. at SkiaSharp.LibraryLoader.LoadLocalLibrary[T](String libraryName) at System.Lazy1.CreateValue() at System.Lazy1.LazyInitValue() at SkiaSharp.SkiaApi.sk_managedstream_set_procs(SKManagedStreamDelegates procs) at SkiaSharp.SKAbstractManagedStream..cctor() --- End of inner exception stack trace --- at SkiaSharp.SKAbstractManagedStream..ctor(Boolean owns) at SkiaSharp.SKManagedStream..ctor(Stream managedStream, Boolean disposeManagedStream) at SkiaSharp.SKCodec.WrapManagedStream(Stream stream) at SkiaSharp.SKBitmap.Decode(Stream stream) at LabMonsterToolkit.SKImageStore.LoadResource(String key, String uri) at LabMonsterToolkit.SKImageStore.LoadResources() at LabMonsterToolkit.SKImageStore..ctor() at LabMonsterToolkit.SKImageStore.GetImageStoreSingle() at LabMonsterToolkit.TrainingWindow..ctor(ControllerInterface controllerInterface) at LabMonsterToolkit.MainWindow.OpenTrainer(Object sender, RoutedEventArgs e) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.Controls.Primitives.ButtonBase.OnClick() at System.Windows.Controls.Button.OnClick() at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent) at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args) at System.Windows.Input.InputManager.ProcessStagingArea() at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport) at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel) at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam) at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at LabMonsterToolkit.App.Main()

I've been searching trying to determine the source of the issue. I installed Skia vis the NuGet installer for the project. The following dlls are included as dependencies in the installer:

  • SkiaSharp.dll
  • SkiaSharp.Views.Desktop.Common.dll
  • SkiaSharp.Views.Desktop.dll
  • SkiaSharp.Views.Gtk.dll
  • SkiaSharp.Views.WindowsForms.dll
  • SkiaSharp.Views.WPF.dll

I can see the dlls are in the application directory for the installed application.

The dlls have the following attributes for the installer: [image: DLL config] https://user-images.githubusercontent.com/319468/239097181-1cdb5447-d853-421a-aebf-713814546b20.PNG

Any help is appreciated. I put a lot of work rewriting my applicaiton to use SkiaSharp and it works great. Hitting this roadblock is very frustrating.

— Reply to this email directly, view it on GitHub https://github.com/mono/SkiaSharp/issues/2463, or unsubscribe https://github.com/notifications/unsubscribe-auth/AALDKFKQY7QTQPSULHZVSGDXGVMW3ANCNFSM6AAAAAAYFXXBKY . You are receiving this because you are subscribed to this thread.Message ID: @.***>

erebuswolf commented 1 year ago

Thank you for the reply. After adding the runtime libs, I now am getting this from my installer log

DEBUG: Error 2727: The directory entry '_412412F434E7471BB49E4F29D2448DDD' does not exist in the Directory table

I'm not sure if this director is needed by skia or something else but it is a weird directory to require for my application. Do you have any clue why it would need this to exist?

Edit: The directory changes names every build, so it must be some auto-generated parth. I'm stumped again.

yuanrui commented 1 year ago

In our old project, has same error. copy nuget packages file "libSkiaSharp.dll" to bin path fixed this problem. It looks sime strange, why not auto copy libSkiaSharp.dll to bin path. .net framework is 4.6.2, platform is anycpu.