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

Started by
6 comments, last by hymerman 17 years, 4 months ago
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!
Advertisement
c dont have classes do they?
Bring more Pain
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.
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 :(
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 DLLextern "C" __declspec(dllexport) setFunctionPointers(  int (*getter)(), void (*setter)(int));// the function pointersint (*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 applicationextern "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.
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 :)
Check this example, explanation follows:
// dll.ccextern "C" {__declspec(dllexport) void setFunctionPointers(int (*getter)(), void (*setter)(int));__declspec(dllexport) void test();}// the function pointersint (*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 applicationextern "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.ccgcc -shared -o dll.dll dll.odlltool -l dll.lib -a -D dll.dll -z dll.def dll.ogcc -c main.ccg++ -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.
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.

This topic is closed to new replies.

Advertisement