Sign in to follow this  

Help seriously needed with seemingly very simple problem (static instances, DLLs)

This topic is 4015 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Seriously, this problem is really, REALLY annoying me now. I thought it would take me a day to solve, but it's been holding me up for the past two weeks now, and as such I am mightily annoyed. Now, all I want to do, is to have a single instance of something, shared between DLLs. I've been making the problem simpler and simpler, and still can't get it to work. I'm now just trying to get an int to change its value when a DLL is loaded. Here's what I have:
//Main.h
#include "Test.h"
int main(){
	std::cout << i;
	LoadLibrary("DLL.dll");
	std::cout << i;
}

// Test.h
__declspec(dllexport) int i;

// DLL.h
#include "Test.h"
extern "C" {
class proxy {
public:
	proxy(){
		i = 5;
	}
};

proxy p;
}

Now, I've been told the reason this doesn't work is that a separate copy of i is being compiled into the app and the DLL, and that I should replace it with an accessor implemented in a source file, but this just gives me an unresolved external symbol linker error. Can someone please point out what I'm doing wrong, or even give me a little code that'll compile, so I can see what I'm supposed to be doing? I'm really tearing my hair out over this one, and I'm far too young to go bald. Please help! Thanks people!

Share this post


Link to post
Share on other sites
So you have a value stored in your DLL, and you want your application access that value. The value cannot be accessed directly, but you have to provide functions to access that value. Your application might look like this:

// declare the function as being in a DLL
__declspec(dllimport) int getValue();
...
int main()
{
int value = getValue();
return 0;
}


Now when compiling the DLL, instead of using "dllimport" you have to use "dllexport", so that the function (or even a class) is visible to the application.

__declspec(dllexport) int getValue();
__declspec(dllexport) void setValue(int newValue);
...
int value;
...
int getValue()
{
return value;
}
void setValue(int newValue)
{
value = newValue;
}




Have you already read this page from the wiki ?
http://en.wikipedia.org/wiki/Dynamic-link_library
There are also some examples.

Share this post


Link to post
Share on other sites
Thanks, that helps quite a lot. I was a bit unclear in my original post though, I actually meant I have some state in the app that I want DLLs to access. I've rearranged and fiddled with the code you posted, but I still can't get it working. It seems I'm just hopelessly inadequate when it comes to DLLs, which is a problem since they're the main focus of my current project...

If it's not too much trouble, would it be possible for somebody to post up a little bit of code that I can copy and paste into my IDE and compile, since everything I write is wrong :(

Share this post


Link to post
Share on other sites
So you want the DLL to read/write a variable of the application ? You can pass a function pointer to the DLL that points to a function that can read/write that variable, then the DLL can use that function pointer to access the variable indirectly.

The code then may look like this (untested):

// for the DLL
extern "C" __declspec(dllexport) setFunctionPointers(
int (*getter)(), void (*setter)(int)
);

// the function pointers
int (*getValue)();
void (*setValue)(int);

setFunctionPointers(int (*getter)(), void (*setter)(int))
{
getValue = getter;
setValue = setter;
}

void test()
{
int i = getValue();
setValue(i + 3);
}


and

// for the application
extern "C" __declspec(dllimport) setFunctionPointers(
int (*getter)(), void (*setter)(int)
);

int value;

int getValue()
{
return value;
}

void setValue(int newValue)
{
value = newValue;
}

int main()
{
setFunctionPointers(getValue, setValue);
...
return 0;
}




Instead of passing around function pointers you may instead provide an implementation for some interface (i.e. in C++ a class with virtual functions), then pass a pointer to that object to the DLL.

Share this post


Link to post
Share on other sites
Well, I tried that code out (after fixing some tiny errors, and separating out into h/cpp files), and I get an unresolved external symbol error -

error LNK2019: unresolved external symbol __imp__setFunctionPointers referenced in function _main main.obj

I thought the __declspec(dllimport) told the compiler/linker that the function was to be found in a DLL?

Thanks for being so patient, I appreciate it a lot :)

Share this post


Link to post
Share on other sites
Check this example, explanation follows:

// dll.cc
extern "C" {
__declspec(dllexport) void setFunctionPointers(int (*getter)(), void (*setter)(int));
__declspec(dllexport) void test();
}

// the function pointers
int (*getValue)();
void (*setValue)(int);

void setFunctionPointers(int (*getter)(), void (*setter)(int))
{
getValue = getter;
setValue = setter;
}

void test()
{
int i = getValue();
setValue(i + 3);
}



// main.cc

#include <iostream>

// for the application
extern "C" {
__declspec(dllimport) void setFunctionPointers(int (*getter)(), void (*setter)(int));
__declspec(dllimport) void test();
}

int value;

int getValue()
{
return value;
}

void setValue(int newValue)
{
value = newValue;
}

int main()
{
std::cout << "value = " << value << std::endl;
setFunctionPointers(getValue, setValue);
std::cout << "value = " << value << std::endl;
test();
std::cout << "value = " << value << std::endl;
return 0;
}



Compile, link and run with:
(using MinGW)

gcc -c dll.cc
gcc -shared -o dll.dll dll.o
dlltool -l dll.lib -a -D dll.dll -z dll.def dll.o
gcc -c main.cc
g++ -o main.exe main.o dll.lib


The DLL exports two functions setFunctionPointers() and test(), both having C linkage. (In the previous example the 'void' was missing, sorry.) The dll.cc is compiled with "gcc -c dll.cc" to an object file "dll.o", then linked to create the DLL with "gcc -shared -o dll.dll dll.o".

With the "dll.dll" itself, runtime linking can be performed by calling LoadLibrary(), then GetProcAddress(). But to make things easier and let the application automatically load all required DLLs a loadtime, an import library "dll.lib" may be created.

This import library contains wrappers for every function that the DLL exports to redirect the call to the DLL. It also contains code to load the library (i.e. calls LoadLibrary()) and to obtain the addresses of the exported functions (via GetProcAddress()). Creation of the import library is done by calling "dlltool -l dll.lib -a -D dll.dll -z dll.def dll.o". This also creates a text file "dll.def", which can be used to check the exported functions.

Compiling the application is done with "gcc -c main.cc", then linking the "main.o" and "dll.lib" to a "main.exe" is performed with "g++ -o main.exe main.o dll.lib". Calling g++ instead of gcc is necessary because a C++ library (iostream) was used and g++ automatically adds the required paths for that library when linking.

Share this post


Link to post
Share on other sites
Ah! It's all clicked into place! Thanks very much for that, it's working now, and I think I understand dynamic libraries too :) Thanks for all your help, I've rated you up.

Share this post


Link to post
Share on other sites

This topic is 4015 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this