The Student Room Group

Reply 1

In order for a function of a dll to be accessible from another dll (or exe) it must appear in the exports table of the dll and you can make this happen in one of three ways. Marking this function as __declspec(dllexport), putting it in the EXPORTS section of the dll's .DEF file or using a /EXPORT switch to link.exe at link time. If the function isn't exported, you can't use it from outside the dll.

Using __declspec(dllimport) isn't quite as simple. Using it correctly eliminates a thunk that would otherwise be required but so long as you link with the exporting dll's import lib (which you need to do in any case) the consuming dll will still build correctly.

Perhaps if you posted some sample code, you could illustrate where it all seems to work and we could see why?

Reply 2

Mathmoid
In order for a function of a dll to be accessible from another dll (or exe) it must appear in the exports table of the dll and you can make this happen in one of three ways. Marking this function as __declspec(dllexport), putting it in the EXPORTS section of the dll's .DEF file or using a /EXPORT switch to link.exe at link time. If the function isn't exported, you can't use it from outside the dll.

Using __declspec(dllimport) isn't quite as simple. Using it correctly eliminates a thunk that would otherwise be required but so long as you link with the exporting dll's import lib (which you need to do in any case) the consuming dll will still build correctly.

Perhaps if you posted some sample code, you could illustrate where it all seems to work and we could see why?

I'm just doing it like this

MyClass.h

#ifndef __MAIN_H__
#define __MAIN_H__

#define CLASSLIB_API __declspec(dllexport)

#include <iostream>

void CLASSLIB_API PrintText();
void CLASSLIB_API Wait();

#endif


MyClass.cpp

#include "MyClass.h"

void PrintText()
{
std::cout << "Hello World\n";
}

void Wait()
{
std::cin.get();
}


main.cpp (in the program using the DLL)

#include "MyClass.h"

int main()
{
PrintText();
Wait();

return 0;
}


In MyClass.h, switching dllimport for dllexport still works for some reason :s-smilie:

Reply 3

When compiling the dll did you get the warning about inconsistent dll linkage with __declspec(dllimport)?

Reply 4

Mathmoid
When compiling the dll did you get the warning about inconsistent dll linkage with __declspec(dllimport)?

Yep, but it still worked, just that warning...

Reply 5

Did you read the warning :wink: ?

Reply 6

Mathmoid
Did you read the warning :wink: ?

Kinda..... :s-smilie:

So is dllimport meant to be used on functions that are being imported from a DLL into another DLL, as a kind of "thru link" if you like?

Reply 7

slugonamission
Kinda..... :s-smilie:

So is dllimport meant to be used on functions that are being imported from a DLL into another DLL, as a kind of "thru link" if you like?

OK, the compiler warning you should have got was C4273 "inconsistent dll linkage".

In other words, when compiling the dll you told the compiler here:

void CLASSLIB_API PrintText();

that the function will be imported from another dll, but here:

void PrintText()
{

you provide a definition for the function, so it's not imported from another dll. To resolve this error the compiler assumes that you meant to export the function from this dll instead.

I don't understand what you mean be "thru link". __declspec(dllimport) is just tells the compiler that the function will be imported from a separate dll, it's not a mechanism to re-export it or anything.

Reply 8

Mathmoid
OK, the compiler warning you should have got was C4273 "inconsistent dll linkage".

In other words, when compiling the dll you told the compiler here:

void CLASSLIB_API PrintText();

that the function will be imported from another dll, but here:

void PrintText()
{

you provide a definition for the function, so it's not imported from another dll. To resolve this error the compiler assumes that you meant to export the function from this dll instead.

I don't understand what you mean be "thru link". __declspec(dllimport) is just tells the compiler that the function will be imported from a separate dll, it's not a mechanism to re-export it or anything.

That's kinda what I meant. A pass-through if you see what I mean. It's hard to explain. Basically declaring the method, but saying it is in a different DLL?

Reply 9

slugonamission
That's kinda what I meant. A pass-through if you see what I mean. It's hard to explain. Basically declaring the method, but saying it is in a different DLL?


To be honest, I can't really see what you trying to get at with with the "pass-through" concept. There are only two "ends" to each import/export relationship no "through" or "middle", there's the module which defines/exports then function and the module which consumes/imports the function. Perhaps I just don't see the things the way you do, though.

Reply 10

Mathmoid
To be honest, I can't really see what you trying to get at with with the "pass-through" concept. There are only two "ends" to each import/export relationship no "through" or "middle", there's the module which defines/exports then function and the module which consumes/imports the function. Perhaps I just don't see the things the way you do, though.

OK, I see what you mean (I think).

What I was trying to get at (which I can hopefully explain better now I am awake :smile: ) is can you declare the function prototype for a function in another DLL, add the dllimport attribute, then the function is accessible from your DLL, but it then loads the code from the other DLL and runs that?

Reply 11

That's it. At it's simplest it works like this. I've ignored the issue of header files shared between the two dlls as it just complicates things.

dll1.cpp

// This function will be exported from this dll
__declspec(dllexport) int func1()
{
// Lots of fun code
}



dll2.cpp (or exe.cpp)

// This function is exported from another dll, but we want to use it from here
__declspec(dllimport) int func1();

int internalFunction()
{
// Lots more fun code

// Call to function in other dll
int b = func1();

// Lots more code
}

Reply 12

Mathmoid
That's it. At it's simplest it works like this. I've ignored the issue of header files shared between the two dlls as it just complicates things.

dll1.cpp

// This function will be exported from this dll
__declspec(dllexport) int func1()
{
// Lots of fun code
}



dll2.cpp (or exe.cpp)

// This function is exported from another dll, but we want to use it from here
__declspec(dllimport) int func1();

int internalFunction()
{
// Lots more fun code

// Call to function in other dll
int b = func1();

// Lots more code
}

Oke, thanks very much :smile:

Technically then, to use functions in DLLs, should you declare the function prototype with dllimport, then use it, or is it just implied if you include a header from the DLL?

Reply 13

slugonamission
Oke, thanks very much :smile:

Technically then, to use functions in DLLs, should you declare the function prototype with dllimport, then use it, or is it just implied if you include a header from the DLL?

Yes you should, although skipping the dllimport is allowed. As for including headers from the other dll, that's a whole other story.

It all depends on how the other dll has been designed. Generally, including a header file which is not part of the dll's public interface (i.e. just part of the dll's source code) is a bad idea and can lead to problems. Some component providers will give you the public header files which declare the functions which should be visible to you, for you. You should use those when they are provided.

It is possible, and usually a good idea to have the dll's public header files part of the dll's build, just to ensure consistency. Usually such header files use some trick like this:

Sample mydll.h:

#ifndef MYDLL_H
#define MYDLL_H

// MYDLL_COMPILE should only be defined when actually compiling MyDll.
// Clients of MyDll must not define this macro

#ifdef WIN32

#ifdef MYDLL_COMPILE
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

#else
// possibly other platform support, e.g. __attribute__ ((visibility("default")))
#define MYDLL_API
#endif

// Functions provided by MyDll:

MYDLL_API void DoIt();
MYDLL_API void DoMore();
MYDLL_API int func1();

// etc. etc.

#endif


Now MyDll.h provides a common API definition which is used when compiling MyDll and by its clients.

Reply 14

Mathmoid
Yes you should, although skipping the dllimport is allowed. As for including headers from the other dll, that's a whole other story.

It all depends on how the other dll has been designed. Generally, including a header file which is not part of the dll's public interface (i.e. just part of the dll's source code) is a bad idea and can lead to problems. Some component providers will give you the public header files which declare the functions which should be visible to you, for you. You should use those when they are provided.

It is possible, and usually a good idea to have the dll's public header files part of the dll's build, just to ensure consistency. Usually such header files use some trick like this:

Sample mydll.h:

#ifndef MYDLL_H
#define MYDLL_H

// MYDLL_COMPILE should only be defined when actually compiling MyDll.
// Clients of MyDll must not define this macro

#ifdef WIN32

#ifdef MYDLL_COMPILE
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif

#else
// possibly other platform support, e.g. __attribute__ ((visibility("default")))
#define MYDLL_API
#endif

// Functions provided by MyDll:

MYDLL_API void DoIt();
MYDLL_API void DoMore();
MYDLL_API int func1();

// etc. etc.

#endif


Now MyDll.h provides a common API definition which is used when compiling MyDll and by its clients.

Aha, I see what the point of the #ifdef was in the example I got.

So what you are saying is that when building the DLL, MYDLL_COMPILE should be defined, and then when using the header as an interface to the DLL, it should not be defined?

Reply 15

slugonamission
Aha, I see what the point of the #ifdef was in the example I got.

So what you are saying is that when building the DLL, MYDLL_COMPILE should be defined, and then when using the header as an interface to the DLL, it should not be defined?


Exactly ;thumbsup;

Reply 16

Mathmoid
Exactly ;thumbsup;

At first glance, I though the #ifdef in the example I was looking over said


#ifdef MYDLL_COMPILE
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllexport)
#endif


And thinking it was a bit pointless, then realizing it was actually dllimport in the second, and wondering what the hell it meant.

Thanks very much, much clearer explanation that anything I've ever found :smile: