//
you're reading...
Programming Issues/Tips

Loading 2 DLLs of the Same Name.

1. Introduction.

1.1 Is it possible to load 2 different DLLs, but of the same name, into the memory space of an application ?

1.2 Despite impressions to the contrary, this is definitely possible.

1.3 This article explains how this can be achieved.

2. The LoadLibrary() API.

2.1 The trick is to use the LoadLibrary() API instead of implicit linking to the DLLs.

2.2 When we load a DLL using the LoadLibrary() API, it is identified in code by a handle (HMODULE).

2.3 The name of the DLL no longer plays any further role.

2.4 This is so even if we load another DLL of the same name via LoadLibrary().

2.5 The only caveat is that this other DLL should be loaded from a disk location different from the first one.

2.6 In code, the 2 DLLs are identified by 2 separate HMODULEs.

3. The GetProcAddress() API.

3.1 The GetProcAddress() is the API to use in order to obtain the address of the exported function from a DLL.

3.2 When you observe the prototype of this GetProcAddress() : 

FARPROC WINAPI GetProcAddress
(
  HMODULE hModule,
  LPCSTR lpProcName
);

you will notice that the first parameter is the HMODULE of the target DLL from which you want to search for a particular function name (the second parameter).

3.3 This implies that you can use 2 different HMODULEs to obtain 2 function address from 2 different DLLs using the same function name.

3.4 Extrapolating this, you can in fact use multiple HMODULEs to obtain multiple function addresses from multiple DLLs using the same function name.

3.5 Hence not only can you load multiple DLLs of the same name, you can also load multiple exported functions (of the same name) from each of these DLLs.

4. Example Code.

4.1 In this section, I shall demonstrate the above-mentioned concepts with some simple example codes.

4.2 The game plan is as follows :

  • Create 2 separate DLLs with the same name (MyDLL.dll say).
  • Each DLL will export one API (GetNumber(), say).
  • GetNumber() will simply return an integer.
  • Each DLL’s GetNumber() will return a unique number different from the others.
  • We create a C++ client application that will load each separate DLL and then each DLL’s GetNumber() function.
  • The C++ client will call each GetNumber() function and print out their values.

4.3 Listed below is the source codes for the GetNumber() function of the first MyDLL.dll :

int __stdcall GetNumber()
{
	return 100;
}

It returns a value of 100.

4.4 Listed below is the source codes for the GetNumber() function of the second MyDLL.dll :

int __stdcall GetNumber()
{
	return 200;
}

It returns a value of 200.

4.5 Each DLL project uses an identical .DEF file which is listed below :

LIBRARY	"MyDLL"
EXPORTS
	GetNumber

4.6 Let’s assume that the DLLs and the C++ client application are copied into separate folders of the following directory structure :

where the client app is copied to “Client”, the first MyDLL.dll into “DLL01” and the second into “DLL02”.

4.7 The following is the source code listing of the C++ client application (named CPPClientApp01.exe) :

// CPPClientApp01.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <iostream>

typedef int (__stdcall *PGetNumber)();

void DoTest()
{
	HMODULE hModDLL01 = LoadLibrary(L"..\\DLLs\\DLL01\\MyDLL.dll");
	HMODULE hModDLL02 = LoadLibrary(L"..\\DLLs\\DLL02\\MyDLL.dll");

	PGetNumber pGetNumber01 = (PGetNumber)GetProcAddress(hModDLL01, "GetNumber");
	PGetNumber pGetNumber02 = (PGetNumber)GetProcAddress(hModDLL02, "GetNumber");

	int int01 = pGetNumber01();
	int int02 = pGetNumber02();

	std::cout << int01 << std::endl;
	std::cout << int02 << std::endl;

	FreeLibrary(hModDLL01);
	FreeLibrary(hModDLL02);

	hModDLL01 = NULL;
	hModDLL02 = NULL;
}

int _tmain(int argc, _TCHAR* argv[])
{
	DoTest();

	return 0;
}

The following is a summary of the pertinent points of the code above :

  • The 2 versions of MyDLL.dll are loaded into the memory space of the CPPClientApp01.exe client application.
  • Separate HMODULE values are used to identify each DLL.
  • The signature of the GetNumber() function is typedef’ed by PGetNumber.
  • We use the 2 separate HMODULEs (hModDLL01 and hModDLL02) to obtain the addresses of the GetNumber() function from each DLL.
  • Of course, we must use separate function pointer variables (pGetNumber01 and pGetNumber02) to hold each function address.
  • Each function is called and the results are stored in separate integer variables (int01 and int02).
  • These are then printout out on the screen.
  • The values are as expected : 100 and 200.
  • The DLLs are then unloaded via a call to FreeLibrary().

4.8 At runtime, via the “Modules” debug window, you can see that there are 2 DLL instances each with the name MyDLL.dll albeit each is from a separate directoy :

5. In Conclusion.

5.1 When a DLL is loaded into memory, its disk location is important in order that the correct version is used.

5.2 However, once loaded, it is identified by its HMODULE handle.

5.3 If the exact same DLL (from the disk location) is loaded a second or more time, only one such DLL will exist in the memory space and the HMODULE returned from LoadLibrary() will be the same.

5.4 Each LoadLibrary() call will increase the lock count of the HMODULE.

5.5 In this case, FreeLibrary() must be called the exact same number of times as LoadLibrary() in order that the DLL be released eventually.

 

Advertisements

About Lim Bio Liong

I've been in software development for nearly 20 years specializing in C , COM and C#. It's truly an exicting time we live in, with so much resources at our disposal to gain and share knowledge. I hope my blog will serve a small part in this global knowledge sharing network. For many years now I've been deeply involved with C development work. However since circa 2010, my current work has required me to use more and more on C# with a particular focus on COM interop. I've also written several articles for CodeProject. However, in recent years I've concentrated my time more on helping others in the MSDN forums. Please feel free to leave a comment whenever you have any constructive criticism over any of my blog posts.

Discussion

3 thoughts on “Loading 2 DLLs of the Same Name.

  1. I want to use Pinvoke a .dll that I have stored in memory. I though about using a memory mapped file, but this does not seem to work … any suggestions?

    Posted by John | November 2, 2012, 8:18 pm
  2. Very Nice article!! Thanks!!

    Posted by Abhimanyu vohra | January 15, 2013, 6:03 am
  3. I made project in C# which can to such thing with C++ dlls https://github.com/asd-and-Rizzo/NRegFreeCom

    [Test]
    [Description(“Loads library from subfolder with dependencies searched in this subfolder”)]
    public void TestDllDependenciesLoading()
    {
    var loader = new AssemblySystem();

    // C# loads C++ from Win32 or x64 subfolder
    var anyCpu = loader.GetAnyCpuPath(loader.BaseDirectory);
    loader.AddSearchPath(anyCpu);
    var module = loader.LoadFrom(anyCpu, “NativeLibraryConsumer.dll”);
    var fn = module.GetDelegate();
    object[] retval;

    Assert.IsTrue(42 == fn(out retval));
    loader.Dispose();
    }

    Posted by dzmitrylahoda | June 28, 2013, 2:26 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: