Delphi Programming Observations

Friday, May 1, 2009

Using DLLs stored as Resources in Delphi programs

There are a few DLLs which my Delphi programs interface to, which were developed in other languages. Using LoadLibrary() and GetProcAddress(), your code can avoid crashing by checking for the existance of the DLL. This also allows storing the DLL as a resource, inside the executable, which you can extract to the filesystem and before calling LoadLibrary() and GetProcAddress().

Extracting the DLL to the filesystem works, but there is a better way: BTMemoryModule. BTMemoryModule allows you to extract the DLL to a TMemoryStream, and use it as a DLL, with BTMemoryLoadLibrary and BTMemoryGetProcAddress.

By not extracting the DLL to the filesystem, file access security issues are avoided. This about.com article suggests outputting the DLL in the same directory as the EXE, which is frowned upon in Windows versions after XP. I wasn’t sure if BTMemoryModule would cause problems with Windows Vista UAC, but I haven’t experienced any.

I have a demo project which demonstrates using BTMemoryModule and dGina.dll to disable the windows taskbar at GitHub (If you don’t use Git, or don’t know what it is, you can click the “download” button on the page to download a Zip file). It compiles (at least) with Delphi 2006, Delphi 2007 and Delphi 2009 (I made minor changes to the BTMemoryModule.pas that I downloaded years ago to work with Delphi2009, but I don’t remember exactly what had to be changed. It was minor though).

posted by Jason at 7:31 pm  

10 Responses to “Using DLLs stored as Resources in Delphi programs”

  1. benok says:

    Hi, I’ve just known your work from about.com’s article.
    I think it’s great !
    But I disappointed that the license is LGPL, because it’s hard to use this for commercial project.

    However, I found the original code’s license was changed to MPL from ver 0.0.2, whose difference between 0.01 is only two lines (except license discription).

    So, could you port the difference from original’s ver 0.0.2 and
    could you change the license to MPL ?



    — D:/tmp/extract/MemoryModule001/MemoryModule.c Thu Dec 02 00:50:52 2004
    +++ D:/tmp/extract/MemoryModule002/MemoryModule.c Fri Apr 08 15:44:22 2005
    @@ -1,23 +1,26 @@
    * Memory DLL loading code
    - * Version 0.0.1
    + * Version 0.0.2
    - * Copyright (c) 2004 by Joachim Bauch / [email protected]
    + * Copyright (c) 2004-2005 by Joachim Bauch / [email protected]
    * http://www.joachim-bauch.de
    - * This library is free software; you can redistribute it and/or
    - * modify it under the terms of the GNU Lesser General Public
    - * License as published by the Free Software Foundation; either
    - * version 2.1 of the License, or (at your option) any later version.
    - *
    - * This library is distributed in the hope that it will be useful,
    - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    - * Lesser General Public License for more details.
    - *
    - * You should have received a copy of the GNU Lesser General Public
    - * License along with this library; if not, write to the Free Software
    - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    + * The contents of this file are subject to the Mozilla Public License Version
    + * 1.1 (the “License”); you may not use this file except in compliance with
    + * the License. You may obtain a copy of the License at
    + * http://www.mozilla.org/MPL/
    + *
    + * Software distributed under the License is distributed on an “AS IS” basis,
    + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
    + * for the specific language governing rights and limitations under the
    + * License.
    + *
    + * The Original Code is MemoryModule.c
    + *
    + * The Initial Developer of the Original Code is Joachim Bauch.
    + *
    + * Portions created by Joachim Bauch are Copyright (C) 2004-2005
    + * Joachim Bauch. All Rights Reserved.

    @@ -203,7 +206,7 @@

    // advance to next relocation block
    - (char *)relocation += relocation->SizeOfBlock;
    + relocation = (PIMAGE_BASE_RELOCATION)(((DWORD)relocation) + relocation->SizeOfBlock);
    @@ -460,7 +463,7 @@

    if (module->codeBase != NULL)
    // release memory of library
    - VirtualFree(module->codeBase, module->headers->OptionalHeader.SizeOfImage, MEM_RELEASE);
    + VirtualFree(module->codeBase, 0, MEM_RELEASE);

    HeapFree(GetProcessHeap(), 0, module);

    • Jason says:

      I changed the license in the header to be MPL.
      The v0.0.2 changes were already in BTMemoryModule.pas

      • benok says:

        Thank you for your very quick reply, and I’m sorry that I forgot checking your reply :-)
        Many thanks again to your work ! I’ll try to use soon.

  2. Hafedh TRIMECHE says:

    Please not that BTMemoryLoadLibrary genreates an exception (Integer overflow) when BTMemoryModule is compiled under Delphi 2010 at :
    l_locationdelta := Cardinal(Cardinal(l_code) – l_old_header.OptionalHeader.ImageBase);
    and the BTMemoryLoadLibrary returns nil Pointer.


    • Jason says:

      Overflow checking is a project setting and the default is off.
      You can try adding a {$Q-} to BTMemoryModule.pas, per Embarcadero Docs.

      I only saw this happen a few times after I turned on “Overflow checking” and turned off “String format checking”, but I switched the options back and forth and later could not reproduce it.

      I don’t have the “Overflow checking” option set in a program that I use every day, and I have never seen a problem. If you have a reproducible test case, I would take a further look.

  3. Hafedh TRIMECHE says:

    How to load a dll that it self uses an InMemory dll ?

    Example : LIBXMLSEC.DLL uses LIBEAY32.DLL. The only way LIBEAY32.DLL to be loaded is to save it to file and then call LIBXMLSEC.DLL.


    • Jason says:

      As far as I know, BTMemoryModule won’t help you to modify the behavior of a compiled DLL, I think you would have to essentially decompile the DLL and patch the part that loads and free’s the other dll, and update function pointer references (and I’m not smart enough to help with that)

  4. steph says:

    this line crashes (exception) on Delphi2007/Windows2008 sp1 32bit standard edition even if executable as the ‘execute as an administrator’ option checked :

    l_successfull := l_DllEntry(Cardinal(l_code),DLL_PROCESS_ATTAcH,nil);

    Everything else seems ok before this line.

    Any suggestion ?


  5. nicolas says:

    Hi Jason,

    i’m using BTMemoryModule in my project to embed a DLL.

    on some PCs the function “PerformBaseRelocation” seems to not work properly.

    On main case the BTMemoryLoadLibary not need to use PerformBaseRelocation, but when this function is used ( in the case l_locationdelta 0 ),

    the f_module in my case seems correctly set (f_module.codebase = $1EF0000)

    so lp_relocation = 0F0D0000
    l_offset = 1D

    so we do
    IncP(PUInt64(IncF(lp_dest, l_offset))^, f_delta);

    so lp_dest = nil (is this normal?) is the desired result?

    at this time f_delta = -235995136 so IncP crach…

    can you help me to understand what should this code do?

    it’s a deadlock issue for me.


    • Jason says:

      Sorry, I just found the BTMemoryModule code somewhere online a while ago, and I’ve never seen errors, so I haven’t looked too closely at it.