Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

System.Drawing.Image.InitFromStream works in editor, not build

Discussion in 'Scripting' started by aliasbb42, May 14, 2018.

  1. aliasbb42

    aliasbb42

    Joined:
    Nov 2, 2013
    Posts:
    4
    I'm loading album artwork from music file tags, by way of the id3lib library. It works perfectly in editor, but when running in a standalone build a constructor within System.Drawing.ComIStreamMarshaler is throwing a
    nullref
    error.

    Code (CSharp):
    1. System.TypeInitializationException: The type initializer for 'ManagedToNativeWrapper' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object
    2.   at System.Drawing.ComIStreamMarshaler+ManagedToNativeWrapper..cctor () [0x00049] in <70ab00ccb3534fe8a18560a2a4d91a73>:0
    3.    --- End of inner exception stack trace ---
    4.   at System.Drawing.ComIStreamMarshaler.MarshalManagedToNative (System.Object managedObj) [0x00000] in <70ab00ccb3534fe8a18560a2a4d91a73>:0
    5.   at (wrapper managed-to-native) System.Drawing.GDIPlus:GdipLoadImageFromStream (System.Runtime.InteropServices.ComTypes.IStream,intptr&)
    6. ...
    What would cause this kind of behavior?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    Two things come to mind:

    - that ManagedToNativeWrapper might be getting stripped at build time. Maybe you can explicitly new up one of those objects somewhere in your code, or else wrassle with the code stripping XML file to tell it not to strip that identifier. First thing would just be turn off stripping entirely, see if it works.

    - possibly that ManagedToNativeWrapper isn't in the .NET 2.0 Subset... if you are using that target .NET.
     
  3. aliasbb42

    aliasbb42

    Joined:
    Nov 2, 2013
    Posts:
    4
    Thanks for the reply, but the princess is in another castle. :(

    My build target is PC. I'm not seeing a setting for stripping levels or finding anything online suggesting that I can adjust that.
    I'm also using .NET 4.6, with Unity 2017.3.1f1, fwiw.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,749
    This might be not so much the actual ctor missing as perhaps you feeding it a null, and in the editor it might not care so much. What are you sending to that interop class, the address of a block of memory you downloaded? Maybe doublecheck that it's not coming back null, i.e., do a hard-assert if it is null in your native code?
     
  5. aliasbb42

    aliasbb42

    Joined:
    Nov 2, 2013
    Posts:
    4
    I've looked and looked and can't find where a null would be introduced without being caught/thrown before this point. The originating call (from within id3lib) boils down to:
    Code (CSharp):
    1. if(_pictureData == null || _pictureData.Length < (64 * 64) ) { return null; }
    2. return Image.FromStream(new MemoryStream(_pictureData, false));
    Image.FromStream would throw an ArgumentException if that MemoryStream was null. I also just tried making a call to Image.FromStream using a local file stream, and I get the same nullref error thrown.

    Looking through the constructor for ManagedToNativeWrapper(IStream managedInterface), the only line that seems a good suspect for throwing a nullref is this one, which relies on System.Runtime.InteropServices for the GCHandle class:

    gcHandle = GCHandle.Alloc(this);
     
  6. aliasbb42

    aliasbb42

    Joined:
    Nov 2, 2013
    Posts:
    4
    I finally gave up on this approach and switched plugins to TagLib-sharp. It's dependency-free and avoids System.Drawing.dll, which Unity has apparently had issues with for a long time. No more error, and it works in the standalone as well as in editor.

    And in case anyone else needs it, a quick bit of code found here can help with getting the album artwork through TagLib.
     
  7. BHSPitMonkey

    BHSPitMonkey

    Joined:
    Sep 14, 2016
    Posts:
    10
    I'm having this exact problem, and don't have the option of hopping to a library that doesn't use System.Drawing. Anyone have any theories?
     
  8. TJD269

    TJD269

    Joined:
    Oct 17, 2017
    Posts:
    19
    Having the EXACT same problem. Errors in build, fine in Editor. Same stack trace and everything. Any ideas?
     
  9. sandro-ixt

    sandro-ixt

    Joined:
    May 2, 2019
    Posts:
    11
    Did anybody find a soloution for this? I´m also facing the exact same issue...
     
  10. doctorpangloss

    doctorpangloss

    Joined:
    Feb 20, 2013
    Posts:
    267
    Don't use things that depend on System.Drawing.

    If you need to, get System.Drawing code from https://github.com/dotnet/corefx/tree/master/src. You shouldn't interact with GDI in your Unity application, so if this is too much, find an alternative library.
     
  11. sandro-ixt

    sandro-ixt

    Joined:
    May 2, 2019
    Posts:
    11
    Thanks for your help. In my case, since System.Drawing is referenced by a external managed plugin I could not replace the calls to it. Completely replacing the plugin does not fit my current scedule, so I decided to dig deeper and actually found a working solution.
    If anyone comes across with the same problem maybe this will help for a quick fix:

    The problem in my case was, that the Api Compatibility Level was set to .NET 4.x Equivalent, but the dll that shipped with the Plugin was still from an older version. Replacing the dll with the correct version should to the trick (as long as you´re not using features of the .NET api that are not supported at all in Unity). The newer versions of the dlls can be found in the installation path of your Unity version under Editor\Data\MonoBleedingEdge\lib\mono\YOUR API VERSION\System.Drawing.dll
    The easier and in my opinion better option to do this is letting Unity choose the dll based on its api level automatically by adding a mcs.rsp file, like described in this post by Microsoft:

    https://docs.microsoft.com/en-us/vi...when-using-the-net-4x-api-compatibility-level

    For .NET 4 (or higher) be sure to name the file csc.rsp instead (https://docs.unity3d.com/Manual/PlatformDependentCompilation.html).
     
    Last edited: Aug 6, 2019
    unity_vwDm_Vj1IF77UA likes this.
  12. delaliog

    delaliog

    Joined:
    Feb 28, 2018
    Posts:
    4
    This is what worked for me. Checked the build settings, compiler version, then added the csc file. Worked a treat! Spent days trying to solve this...!!!