Wednesday, September 21, 2011

How to release unmanaged library loaded into managed .NET code

Motivation

I had found this article on how to release DLL library already loaded into the process using P-Invoke. It uses LoadLibrary() and FreeLibrary() WINAPI calls to achieve this.

And what is wrong with it?

It forces to unload ALL instances of the DLL library currently loaded within process. Which means, that in the case you have more than one instance of the class using these external functions ALL these will stop working!

And that is not all - you cannot use this DLL in same application domain again after unloading.

Solution

Solution is pretty simple one, but I have to say that it wasn’t very obvious to me at the beginning.
You can use P-Invoke to import following standard WinAPI functions for dynamical function loading:

  • LoadLibrary()
  • FreeLibrary()
  • GetProcAddress()

We will use following wrapping class:

internal static class UnsafeMethods
{
    [DllImport("kernel32.dll", SetLastError = true)]
    internal extern static IntPtr LoadLibrary(string libraryName);
    [DllImport("kernel32.dll", SetLastError = true)]
    internal extern static bool FreeLibrary(IntPtr hModule);
    [DllImport("kernel32.dll", SetLastError = true)]
    internal extern static IntPtr GetProcAddress(IntPtr hModule, string procName);
}

We also need signatures of imported functions - we will convert them into delegates (following ones come from sample project):

// int multiply(int value1, int value2);
private delegate int MultiplyDelegate(int value1, int value2);
// int str2int(const char *input);
private delegate int Str2IntDelegate([MarshalAs(UnmanagedType.LPStr)]string source);

Now we can create implement our class calling external DLL functionality with IDisposable interface so it will automatically release used DLL library when it will go out-of-scope or it will be finalized (in example project are two functions which we will publish as Multiply() and Str2Int()).

public class ExternalHelpers: IDisposable
{
    #region Private members
    private IntPtr _libraryHandle;
    private MultiplyDelegate _multiply;
    private Str2IntDelegate _str2Int;
    #endregion

    #region External functions delegates
    // int multiply(int value1, int value2);
    private delegate int MultiplyDelegate(int value1, int value2);
    // int str2int(const char *input);
    private delegate int Str2IntDelegate([MarshalAs(UnmanagedType.LPStr)]string source);
    #endregion

    public ExternalHelpers()
    {
        // dynamically load DLL using WinAPI
        _libraryHandle = UnsafeMethods.LoadLibrary(@"testing.dll");

        if (_libraryHandle == IntPtr.Zero)
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        // import functions as delegates using GetProcAddress
        _multiply = LoadExternalFunction<MultiplyDelegate>(@"multiply");
        _str2Int = LoadExternalFunction<Str2IntDelegate>(@"str2int");
    }

    public int Multiply(int value1, int value2)
    {
        // call method using delegate
        return _multiply(value1, value2);
    }

    public int Str2Int(string source)
    {
        // call method using delegate
        return _str2Int(source);
    }

    public void Dispose()
    {
        Dispose(true);

        GC.SuppressFinalize(this);
    }

    ~ExternalHelpers()
    {
        Dispose(false);
    }

    #region Private helper methods
    private T LoadExternalFunction<T>(string functionName)
        where T: class
    {
        Debug.Assert(!String.IsNullOrEmpty(functionName));
        // load function pointer
        IntPtr functionPointer = UnsafeMethods.GetProcAddress(_libraryHandle, functionName);

        if (functionPointer == IntPtr.Zero)
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        // Marshal to requested delegate
        return Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(T)) as T;
    }

    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            _multiply = null;
            _str2Int = null;
        }

        if (_libraryHandle != IntPtr.Zero)
        {
            if (!UnsafeMethods.FreeLibrary(_libraryHandle))
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); 

            _libraryHandle = IntPtr.Zero;
        }
    }
    #endregion
}

And finally - we can use it:

static void Main(string[] args)
{
    using(ExternalHelpers e = new ExternalHelpers())
    {
        const int value1 = 2;
        const int value2 = 3;
        const string strValue = "345";

        Console.WriteLine("{0} * {1} = {2}", value1, value2, e.Multiply(value1, value2));
        Console.WriteLine("{0} => {1}", strValue, e.Str2Int(strValue));
    }

    Console.ReadKey();
}

Looks easy? Yes it is :-)

Links

Sunday, September 11, 2011

Dovolená Deštné v Orlických horách

Na dovolené v Deštném nám skoro nepršelo. S sebou jsme vezli dvě kola, dětskou sedačku na kolo, kakao a jinak skoro nic. Bydleli jsme v malé horské chatičce s akumulačníma kamnama, které nám paní z kempu druhý den zapnuly. A tak jsme od druhého dne měli trvale krapet horko (přeci jenom než jsme si zvykli na jejich setrvačnost, tak nám to trochu trvalo).

Kemp celkově byl úžasný, jenom to pivo a jídlo v kempové restauraci bylo trochu slabší. Kempové paní byly moc hodné a ochotné. Pro děti tam měli velký kulatý stan na hraní, klouzačky, trampolínu a dětský koutek v hospodě, v lese bylo dřevo na táborák a pod okny tekl potůček. Ze zahrádky byl výhled rovnou na dětské hřiště. A po celém kempu opravdu fungoval zdarma internet.

Ke snídani jsme si dávali na co jsme měli chuť - vajíčka, párečky, šunčičku a Kryšťovi tam vařili jeho oblíbené kakó. Obědy jsme si dávali různě tam, kde jsme zrovna byli na výletě a na večeře jsme většinou chodili do restaurací po okolí. Tam taky měli děti rádi. Kryštoví se nejvíc líbilo v protějším penzionu, kde hladil ježečka.

Kryšťa si vymyslel, že chce jet lanovkou a tak jsme nakonec dvakrát jeli na lanovku do Říček, kde se na kopci cpal borůvkami a dokonce tam ušel nějaký ten kilometr (trochu s brekem, ale to nám velkým nevadilo). Celý týden jsme se snažili sbírat pohádková razítka.

Jednou jsme šli pěšky ze Šerlichu na chatu Šerlišský mlýn (no dobrá - bylo to s kopce a tak to odťapal i Kryšťa. Tomu se na Šerlišském mlýně líbil hlavně systém jezírek a potůčků, kde pilně studoval fyzikální zákony vodních proudů. K obědu jsme si tam dali svíčkovou a sladké knedlíky. Paní servírka tvrdila, že už tam pracuje 30 let, takže jsem ji tam nejspíš potkal i během všech předchozích návštěv (jednou když jsem byl malý - taky mám dětskou fotku od mlýnského kola, jednou s Terkou na kole a teď jsme tam byli potřetí).

Krom toho jsme také byli na výletě v Polsku. Tam jsme si prošli rašeliniště, neboli Torfovisko, 5krát s Kryšťou vylezli na vyhlídkovou věž a tak.

Zajeli jsme se podívat i za tetou Monikou do Letohradu. Cestou jsme měli drobnou blinkací nehodu v serpentinách (nějak jsme nepochopili, že chci domů znamená chci blinkat). V Letohradě jsme navštívili muzeum řemesel, kde jsme půl hodiny pouštěli betlém, teta Monika nám ukázala svůj luk a kytaru.

Na Častolovickém zámku jsme si prohlédli nádvoří a hlavně park s divokým prasetem, srncem a jelenem a taky minizoo (v té měli mini prasátka).

Já jsem si užil i kolo, přeci jenom není nad horskou silniční cyklistiku.

Výlety
  • Lanovka s letním provozem v Říčkách v Orlických horách
    • Káry
    • Koloběžky
    • Pro pěší cesta nahoru za mírný poplatek, dolů zdarma, provoz pouze v celou hodinu, nahoře prima borůvky
  • Šerlich - Masarykova chata
    • Nahoře na Šerlichu je parkoviště, kde se nechá zastavit, následuje příjemná procházka z kopce dolů na chatu Šerlichův mlýn, kde mají vodní kolo, vodníka a jezírka.
  • Zámek Častolovice
    • Tady mají mini-zoo a zvěřinec a taky jelena a divoké prase.
    • Prohlídku zámku jsme vynechali.
  • Letohrad 
    • Muzeum řemesel s pohyblivým betlémem řemesel
  • Torfovisko
    • malá procházka rašeliništěm cca 30km od kempu v Polsku. Krásná vyhlídková věž, na kterou jsme několikrát vylezli. Bohužel cesta zpátky vyžaduje kvůli jednosměrce objížďku cca 15km.

Cyklistika

Cyklistika (tedy ta moje oblíbená - silniční) neměla chybu. Zejména pro milovníky kopců - v okolí Deštného totiž neexistuje rovinka a tak prostě člověk jezdí pořád nahoru a dolů, ale stojí to za to. Projížďky dále jsou víceméně na 2 - 2.5 hodiny ostřejší jízdy, ale musím říct, že jsem se nenudil. Nejnáročnější výjezd je asi na Šerlich, ale na druhou stranu pak následuje krásný dlouhý sjezd.

Deštné - Nedvězí - Kounov - Dobruška - Opočno - Trnov - Solnice - Skuhrov nad Bělou - Deštné
59km, převýšení 1098 m, v Dobrušce je nejbližší lékárna od Deštného.

Deštné - Šerlich - Říčky - Rokytnice - Nebeská rybná - Deštné
54 km, převýšení 1280m

Deštné - Zdobnice - Rokytnice v Orlických Horách - Rychnov nad Kněžnou - Solnice - Skuhrov - Deštné
62km, převýšení 1312m
Deštné - Šerlich - Orlické Záhoří - Zieleniec (PL) - Olešnice - Sedloňov - Dobřany - Deštné
54 km, převýšení 1157m

Kemp

Friday, June 10, 2011

SQL Express 2008 Error 'User does not have permission to perform this action' for user instance

Recently I realized that I cannot use user instance feature of SQL Express 2008 R2 on my development machine.

SQL Server was throwing an error 'User does not have permission to perform this action'.

After some time trying to solve it out, I recalled that I was playing with communication protocols some time ago. And really, I got it solved...

I had disabled 'Named pipes' network communication protocol which is used for communication with user instances.

(SQL Server instance MUST be restarted after this change).