ScintillaNET.dll as a single dll (with SciLexer.dll and SciLexer64.dll as embedded resource)

Topics: Developer Forum, Project Management Forum, User Forum
Sep 16, 2013 at 12:59 PM
Hi,

In order to avoid multiple dll's that needs to be shipped with ScintillaNET library, I made a changes in ScintillaNET project and embed SciLexer dll's as ScitntillaNET resource files. I used DynamicNativeLibrary class from Microsoft.WinAny.Helper library to load SciLexer dll's from the memory ( resource / byte array ).

So, SciLexer dll's are now embedded as resource files and loaded from the resource based on the running process ( 32-bit or 64-bit ).

This also fixes UI designer problem when SciLexer dll's could not be found / loaded.

Just to make clear, DynamicNativeLibrary acts like LoadLibrary, but instead of the path, it loads a library from the memory byte array.

Link to the modified: ScintillaNET source code: ScintillaNET-source.zip
Link to the sample binaries: ScintillaNET-binaries.zip

Changes that i made was:
  1. Added Microsoft.WinAny.Helper folder with code files to the ScintillaNET project ( you can get them in source code from the link above )
  2. Added SciLexer.dll and SciLexer64.dll as resource files. (also shown in source from the link)
  3. Changed Scintilla.cs:
// added required namespace
using Microsoft.WinAny.Interop;

// added static variable
private static DynamicNativeLibrary _dynamicModule;

// removed as not needed any more
//private static IntPtr _moduleHandle;

// changed completely
private static void LoadModule()
{
    if (_dynamicModule == null)
    {
        if (IntPtr.Size == 4)
        {
            _dynamicModule = new DynamicNativeLibrary(global::ScintillaNET.Properties.Resources.SciLexer);
        }
        else
        {
            _dynamicModule = new DynamicNativeLibrary(global::ScintillaNET.Properties.Resources.SciLexer64);
        }
    }

    if (_sciFunction == null)
    {
        _sciFunction = _dynamicModule.GetDelegateForFunction("Scintilla_DirectFunction", 
            typeof(NativeMethods.Scintilla_DirectFunction)) as NativeMethods.Scintilla_DirectFunction;
    }
}

public static void SetModuleName(string moduleName)
{
    const string paramName = "moduleName";

    if (moduleName == null)
        throw new ArgumentNullException(paramName);

    if (moduleName.Length == 0)
        throw new ArgumentException(string.Format(Resources.Culture, Resources.Exception_EmptyStringArgument, paramName), paramName);

    // earlier here was _moduleHandle checking, now it's _dynamicModule
    if (_dynamicModule != null)
        throw new InvalidOperationException(Resources.Exception_ModuleAlreadyLoaded);

    _moduleName = moduleName;
}
Coordinator
Sep 17, 2013 at 7:40 PM
Wow!

That someone actually wrote a library to emulate the PE loader and dynamic linker in Windows is incredible. I remember researching this topic a year or two ago as a way of packing the native Scintilla DLL with our managed package but abandoned the idea because it was too much work. It's cool to know that is possible.

However, I can't comfortably make this an approach we use for official distributions. I did a little digging and found the Microsoft.WinAny.Helper library and DynamicNativeLibrary implementation are ports of the C MemoryModule library:
http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/
https://github.com/fancycode/MemoryModule

Digging through the outstanding issues reported on GitHub for this project it appears that the emulated PE loader has issues with Structured Exception Handling in native C/C++ libraries... the particular issue being that catch blocks in native libraries don't execute and instead terminate the process:
https://github.com/fancycode/MemoryModule/issues/4

A cursory glance at the native Scintilla C/C++ code reveals that try/catch blocks are used throughout and so there is the potential that loading the DLL this way could cause application instability.


Jacob
Sep 20, 2013 at 10:15 AM
I did not saw SciLexer source code and did not know that it use try/catch block.
When i catch some time i will try to extend Microsoft.WinAny.Helper DynamicNativeLibrary and implement PEB (Process Environment Block) handling which will allow sage try/catch block.