Visual C++ Dllexports and Dllimports : How can we and how not?  

Posted by Unknown in

                                         I don't know wether that would be a cool way to start of the blog, but then this blog is to help others and since I had to really work hard to get my basic dlls working with Visual Studio 2005, using C++, i thought this gotto be in my blog. So here goes.....(I am writing all this best to my knowledge and do not claim it to be absolutely correct. I am still a college student so forgive em but do tell me if anything is wrong.)

DLLs What and Why?

This I am copying from Microsoft's definition of the dll, but well otherwise you would have said incomplete. 

A dynamic-link library (DLL) is an executable file that acts as a shared library of functions. Dynamic linking provides a way for a process to call a function that is not part of its executable code. The executable code for the function is located in a DLL, which contains one or more functions that are compiled, linked, and stored separately from the processes that use them. DLLs also facilitate the sharing of data and resources. Multiple applications can simultaneously access the contents of a single copy of a DLL in memory.

In my words, DLL is just a set of classes and functions that we think are required to be seperate from the main program for whatever the reason, let it be reuse, memory, distribution, cross-platform use etc.  So set out and build your first DLL.

Note that dlls are of two types: Static and Dynamic. A static dll is the one which has to be loaded at the compile time while the dynamic can be loaded at the run time.

What can you export?

You can export functions, classes, member elements from inside a dll. since the process involved is almost similar, i'll be demonstarting only the export of functions.

Building a CPP DLL: Building a CPP dll is not at all tough using visual studio. 

  1. Select File>New>Project.
  2. Select Visual C++>Win32/Smart Device>Console Application.
  3. In the Application Settings select DLL, Export symbols.
  4. With this you will get to a file where everything would be set up.
  5. In the file produced it will have already a definition of an exported variable, function as well as a class. so u can use that rename that and do whatever you wish to.
  6. Remember keeping a track of the header file present as that header file will need to contain information about your exports.

Sample C file generated

Header File

Because I think you would have got my point so I'm copying down the filename and the code from MSDN:

// MathFuncsDll.h

namespace MathFuncs
{
  class MyMathFuncs
  {
  public:
  // Returns a + b
__declspec(dllexport) double Add(double a, double b);

  // Returns a - b
 __declspec(dllexport) double Subtract(double a, double b);

  // Returns a * b
   __declspec(dllexport) double Multiply(double a, double b);

  // Returns a / b
  // Throws DivideByZeroException if b is 0
 __declspec(dllexport) double Divide(double a, double b);
  };
}

// MathFuncsDll.cpp

#include "MathFuncsDll.h"

#include

#include "stdafx.h"
using namespace std;

namespace MathFuncs
{
  double MyMathFuncs::Add(double a, double b)
  {
  return a + b;
  }

  double MyMathFuncs::Subtract(double a, double b)
  {
  return a - b;
  }

  double MyMathFuncs::Multiply(double a, double b)
  {
  return a * b;
  }

  double MyMathFuncs::Divide(double a, double b)
  {
  if (b == 0)
  {
  throw new invalid_argument("b cannot be zero!");
  }

  return a / b;
  }
}

The new terms you might have faced include the '__declspec' and 'dllexport'. You might be able to guess 'dllexport' as to be requiring for export. __declspec is calling convention for the function, for a detailed note on which refer here or you can refer to MSDN

Issue of Name Mangling:Name mangling is the concept where the function is referred to using some terms more than the function name. Basically it is not enough in case of overloading, that we can refer to a function by its name. So the only way to refer to a function was via the full prototype. Now due to the problem of the presence of spaces in prototype and a deliberate attempt to save size, some encryption was done to the code resulting in a mangled code. For example:?terminate@std@@YAXXZ  is the mangled name to void __cdecl std::terminate(void). You can refer to more about this in wikipedia.  

Why I giving you all this is so that you don't have confusion in case you have error messages and also because mangling differentiate's between a C type and a C++ or OOPs type export. 

Also note that you have an option of having an undecorated(or unmangled) code in C++, by using the extern "C" words in the exports, such that the new header has:

extern "C" __declspec(dllexport) double Add(double a, double b);  

instead of  __declspec(dllexport) double Add(double a, double b);

Using CPP to import a CPP DLL: The DLLs can be loaded by other progg. languages as well. But here I write how to load it in CPP, which I think is the reason this article is here. I thas not been updated well on the web and that's why people have been facing problems.

Okay, so here it is... A dll once created can be referenced in another in two ways:

1) Static Linking                           2) Dynamic Linking.

Static Linking: Static linking is when the dll gets imported at compile time. The functions are not loaded but the compiler has an idea of which dll to import and indeed it is reference in the code. Static Linking is normally associated with static libraries (.lib files) but since it is possible with dlls, I don't mind mention it here.

  1. Select File>New>Project
  2. Select Visual C++>Win32/Smart Device>Console Application.
  3. There you are ready to set up stuff.

But static linking does not take place as easily in visual C++, as compared to visual C#, i don't know why. MSDN talks of adding references from add reference but no such references are vailable. That's where people are stuck up many times. Okay so, what you have to do is forget that article,

     4.  Go to Project>Add Existing Item><>

     5. Do all files and select the .lib file.

The .lib file to be selected.

This vital step links out the dll to your project. Now you can write your code which again i am copying from MSDN.

// MyExecRefsLib.cpp

#include "stdafx.h"

#include "MathFuncsLib.h"

using namespace std;

int main()
{
  double a = 7.4;
  int b = 99;

  cout << "a + b = " <<   MathFuncs::MyMathFuncs::Add(a, b) << b = " <<   MathFuncs::MyMathFuncs::Subtract(a, b) << endl;   cout << " b = " <<   MathFuncs::MyMathFuncs::Multiply(a, b) << endl;   cout << " b =" ">

where the unmentioned MthFuncsLib. h is:

// MthFuncsLib. h

namespace MathFuncs
{
  class MyMathFuncs
  {
  public:
  // Returns a + b
  static __declspec(dllimport) double Add(double a, double b);

  // Returns a - b
  static __declspec(dllimport) double Subtract(double a, double b);

  // Returns a * b
  static __declspec(dllimport) double Multiply(double a, double b);

  // Returns a / b
  // Throws DivideByZeroException if b is 0
  static __declspec(dllimport) double Divide(double a, double b);
  };
}
(Note that we will require the static keyword to be present in the library definition as well)

If you compile and run this you get the output as specified at MSDN:

a + b = 106.4
a - b = -91.6
a * b = 732.6
a / b = 0.0747475
 Of course you will need your dll to be present in the debug/release folder.

Dynamic Linking: Dynamic Linking is runtime, that is the process is loaded at the runtime. The compiler has no clue which dll will be loaded and its actual address is referenced in the code. i am not sure functions exported from within the class can be as easily accessed dynamically as from outside or as is the whole class. Thus I am using the function present outside the code of the class:

// AddDll.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "AddDll.h"
#include
#include

BOOL APIENTRY DllMain( HANDLE hModule, 
  DWORD ul_reason_for_call, 
  LPVOID lpReserved )
{
 switch (ul_reason_for_call)
 {
 case DLL_PROCESS_ATTACH:
 case DLL_THREAD_ATTACH:
 case DLL_THREAD_DETACH:
 case DLL_PROCESS_DETACH:
  break;
}
 return TRUE;
}


// This is an example of an exported function.
      ADDDLL_API int Add(int a,int b)
     {
                 return (a+b);
     }
     ADDDLL_API float Add(float a,float b)
     {
                 return a-b;
     }
}

//AddDll.h

#ifdef ADDDLL_EXPORTS
#define ADDDLL_API extern "C" __declspec(dllexport)
#else
#define ADDDLL_API __declspec(dllimport)
#endif

ADDDLL_API int Add(int a,int b);
Again for dynamic loading you 'll need to follow the basic step:

  1. Select File>New>Project
  2. Select Visual C++>Win32/Smart Device>Console Application.
  3. There you are ready to set up stuff.

Now you can write down the to access the dll dynamically:

//CallAddDll.cpp

#include

#include "stdafx.h"

using namespace std;

int main()
{  

       typedef int (__cdecl *ptrFunc) (int, int) ;
       ptrFunc Add;
       HINSTANCE handle = LoadLibrary(L"C:\\AddDll.dll") ;
       if(handle!=NULL)       {
                   Add= (ptrFunc) (GetProcAddress(handle,L"Add") );
                    if(Add!=NULL)
                     {
                                    printf("Result = %d",Add(4,5));
                      }
                       else
                      {
                                    printf("Could Not Load Function! Add");
                       }

       }
       else
       {
                           printf("Could not attach DLL!");
       }

       FreeLibrary(handle);
       return 0;

}

I hope you got a basic idea, for all those who needed help. all suggestions are welcome......

This entry was posted on Wednesday, July 16, 2008 at Wednesday, July 16, 2008 and is filed under . You can follow any responses to this entry through the comments feed .

0 comments

Post a Comment