FileOnQ / Imaging.Heif

A C#/.NET wrapper around libheif for decoding and processing high efficiency image formats (heif, heic).
GNU Lesser General Public License v3.0
15 stars 4 forks source link

DllNotFoundException When Writing - FileOnQ.Imaging.Heif.Encoders #37

Closed kenny-sellers closed 2 years ago

kenny-sellers commented 2 years ago

Updated Description

By: @ahoefling

The libjpef-turbo dependency is being compiled in debug mode which uses the Visual C Runtime, this makes the entire library dependent on debug binaries that are NOT included in the Visual C++ Redistributable package. We need to ensure all projects in this library are compiled in release mode.

Original Post

The Library is throwing a DLL not found error. This appears to be due to SetDLLDirectory not working correctly. We should switch over to using AddDLLDirectory instead.

SkyeHoefling commented 2 years ago

It appears the latest NuGet (1.0.0-dev.15) package is dependent on vcruntime140d.dll by the way of jpeg62.dll. I investigated all dlls generated for dependency to see if there is another redistributable package to be installed downstream.

dumpbin /dependents jpeg62.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30038.1
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file jpeg62.dll

File Type: DLL

  Image has the following dependencies:

    VCRUNTIME140D.dll
    ucrtbased.dll
    KERNEL32.dll

  Summary

        1000 .00cfg
        2000 .data
        1000 .idata
       44000 .rdata
        3000 .reloc
        1000 .rsrc
       93000 .text

vcruntime140d.dll is the Visual C Runtime DEBUG dll which is part of a Visual C++ development environment but not part of the Visual C++ redistributable package. In #24 we updated the FileOnQ.Imaging.Heif.Encoders project to compile under release mode which fixes problems where we needed to compile libjpeg-turbo in debug mode. In my local testing I was able to compile everything in release mode and test in a clean virtual machine.

Virtual Machine Testing Notes

To properly test this out, I created a clean Windows 10 Virtual Machine and copied over the compiled console application for .NET Framework 4.8 targeting CPU x86.

Test 1 - DllNotFoundException - heif.dll

The first test I didn't do anything to the environment and just ran the console app to see what would happen. A DllNotFoundException was thrown saying that it could not load heif.dll.

Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'heif.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
   at FileOnQ.Imaging.Heif.LibHeif.x86.heif_context_alloc()
   at FileOnQ.Imaging.Heif.LibHeif.ContextAllocate()
   at FileOnQ.Imaging.Heif.HeifImage..ctor(String file)
   at ConsoleApp.Program.Main(String[] args) in D:\FileOnQ.Imaging.Heif\samples\ConsoleApp\ConsoleApp.Shared\Program.cs:line 11

To resolve this issue - install the Visual C++ Redistributable package for x86. If you are running it on x64 you'll need to install that redistributable as well.

Test 2 - DllNotFoundException - FileOnQ.Imaging.Heif.Encoders.dll

This test is ran after installing the redistributable package which got us a little bit further along.

Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'FileOnQ.Imaging.Heif.Encoders.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
   at FileOnQ.Imaging.Heif.LibEncoder.x86.encoder_jpeg_init(Int32 quality)
   at FileOnQ.Imaging.Heif.LibEncoder.InitJpegEncoder(Int32 quality)
   at FileOnQ.Imaging.Heif.Image.CreateEncoder(Int32 quality)
   at FileOnQ.Imaging.Heif.Image.Write(String filename, Int32 quality)
   at ConsoleApp.Program.Main(String[] args) in D:\FileOnQ.Imaging.Heif\samples\ConsoleApp\ConsoleApp.Shared\Program.cs:line 27

To resolve this, I compiled libjpeg-turbo in release mode and everything started working.

Why Didn't We See This Earlier?

The CI build runs integration tests on the GitHUb Action Runner which comes pre-installed with a Visual Studio development environment. This includes the necessary Visual C Runtime debug dlls such as vcruntime140d.dll. The integration test produced a false positive that wasn't noticed until we tried handing downstream projects off to QA. At this point, I don't think we can catch this via the hosted runners but have created a backlog item to track improvement on integration testing, see #39

SkyeHoefling commented 2 years ago

We need to add documentation to the README that clearly states the windows binaries require the Visual C++ redistributable packages. I have created a new documentation task to track this #40

SkyeHoefling commented 2 years ago

This issue is already documented in #2 and will be resolved once a PR is submitted for that and merged