Sign in to follow this  
Subotron

C++ DLL: export instance of class, but not class itself

Recommended Posts

What I want to do is make a DLL for a certain module, that can be used, but there is only one instance of it at all time. PLEASE don't give an answer that involves the world 'singleton' :). My thought was to define a class, but only export a global instance of it:
#ifdef DLL_EXPORTS
#define PUBLIC __declspec(dllexport)
#else
#define PUBLIC __declspec(dllimport)
#endif

class CClass
{
public:

	CClass()	{ }
	~CClass()	{ }
};

PUBLIC CClass instance;


However, this doesn't seem to work. Either it is just not possible to export an instance of a class that isn't exported, or something is wrong in the header file which I constructed to go along with the lib/DLL. This is the header file:
#define PUBLIC __declspec(dllexport)

class CClass
{
public:

	CClass()	{ }
	~CClass()	{ }
};

PUBLIC CClass instance;


You might notice the PUBLIC definition is different in this header, but leaving it as it was gave linking errors in the project that used the DLL. Who can help me solve this? P.S.: As you might have noticed, I'm a total noob to DLLs.

Share this post


Link to post
Share on other sites
Provide a function that returns an instance of your class. You can hide the fact that is actually is a class by typedef'ing the pointer to something like: CLSINSTANCE.

Unfortunately, you will have to provide functions to call the class methods to retain your secret class.

Happy coding!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
A global is technically what a singleton is lol.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
How do you want to use your instance without the class definition?

Share this post


Link to post
Share on other sites
That is my question... it's more a scope issue, I'm not sure what is known to a program using a library file, so I was just wondering if this was possible. The class IS defined when the instance is created, its just not exported by itself.

Share this post


Link to post
Share on other sites
In order for your application to use the class methods of the class defined in the DLL, the class needs to be exported from the DLL. If you don't export/import the class definition, you'll get linker errors. Because of this, you can't export an instance without exporting the class as well.
I think you best bet is to use a pure virtual base class. This type does not need to exported from the DLL!
So in the application the DLL global is declared as:

#include "iclass.h"
__declspec(dllimport) IClass *instance;

and the "iclass.h" is:

class IClass
{
public:
virtual void Foo (void) = 0;
// etc....
};

In your DLL you will need to set up the instance pointer correctly:

#include "iclass.h"

class Class : public IClass
{
virtual void Foo (void);
// etc....
};

Class g_instance;

__declspec(dllexport) IClass *instance = &g_instance;


Notice that the declaration is not in the same header file, only the definition of the pure virtual base class is shared.

Here's a description of how the compiler finds symbols with DLLs.

Skizz

Share this post


Link to post
Share on other sites
As has been noted, exporting an instance without the class definition doesn't make any sense: how is the importer going to use something if it doesn't know anything at all about what it is?

But never mind all that. I think the real question is: where did you get the idea that "module" implies "class"? Think about e.g. how std::rand() works. Is there some global object? Presumably so: the seed. Do you have raw access to it? Nope. How is the interface done? global, free (as opposed to member) functions. These are created according to the usual rules of interface design: invariants are maintained internally, so that you can call the provided functions as you like - and you are, conversely, only offered the functions that you could use safely.

Share this post


Link to post
Share on other sites
I apologize for not giving you a more direct solution... I can think of only two things you are trying to do:

1. Export a single instance of a class to access it's members (and yes, this is a Singleton). NOTE: I didn't add the memory cleanup to reduce the code size. The DLL must free the memory it created otherwise a memory leak will occur. The application can't delete the memory since the memory spaces are different, doing so will cause the application to crash.

simpleClass.h (DLL project)

#ifdef SIMPLEDLL_EXPORTS
#define SIMPLEDLL_API __declspec(dllexport)
#else
#define SIMPLEDLL_API __declspec(dllimport)
#endif

class SIMPLEDLL_API SimpleClass
{
private:

static SimpleClass* instance;

SimpleClass();

public:

void DoSomething();

static SimpleClass& getInstance();

};



simpleClass.cpp (DLL project)

#include "simpleClass.h"
#include <iostream>

SimpleClass* SimpleClass::instance = NULL;

SimpleClass::SimpleClass()
{
}

SimpleClass& SimpleClass::getInstance()
{
if( instance == 0 ) {
instance = new SimpleClass();
}
return *instance;
}

void SimpleClass::DoSomething()
{
std::cout << "I just did!" << std::endl;
}



main.cpp (Application using the DLL)

#include "stdafx.h"
#include "simpleClass.h"

int _tmain(int argc, _TCHAR* argv[])
{
SimpleClass::getInstance().DoSomething();
return 0;
}




2. Export an Facad class allowing you access to internal data that only you have access too. (NOTE: I do not recommend this approach since it a pain to manager and any object differences between the DLL and an application will cause havoc! I really don't recommend this approach, heck I wouldn't have suggest it! I only want to show you a different way of doing what you may want to do, but this can be a nightmare, so do try to avoid it if the the first solution can be used (and probably should be used).

NOTE: I didn't add the memory cleanup to reduce the code size. The DLL must free the memory it created otherwise a memory leak will occur. The application can't delete the memory since the memory spaces are different, doing so will cause the application to crash.

simpleClass.h (DLL)

#pragma once

#ifdef SIMPLEDLL_EXPORTS
#define SIMPLEDLL_API __declspec(dllexport)
#else
#define SIMPLEDLL_API __declspec(dllimport)
#endif

class SIMPLEDLL_API SimpleClass
{
private:

static void* instance;

SimpleClass();

public:

static void* getInstance();

};



simpleClass.cpp (DLL)

#include "simpleClass.h"
#include "hiddenSimpleClass.h"

void* SimpleClass::instance = 0;

SimpleClass::SimpleClass()
{
}

void* SimpleClass::getInstance()
{
if( instance == 0 ) {
instance = new HiddenSimpleClass();
}
return instance;
}



hiddenSimpleClass.h
NOTE: This has to be in both the DLL and the application.

#pragma once

class HiddenSimpleClass
{

public:

HiddenSimpleClass();

void DoSomething();

};



hiddenSimpleClass.cpp
NOTE: This has to be in both the DLL and the application.

#include "hiddenSimpleClass.h"
#include <iostream>

HiddenSimpleClass::HiddenSimpleClass()
{
}

void HiddenSimpleClass::DoSomething()
{
std::cout << "I just did!" << std::endl;
}



main.cpp (The application accessing the DLL)

#include "stdafx.h"
#include "simpleClass.h"
#include "hiddenSimpleClass.h"

int _tmain(int argc, _TCHAR* argv[])
{
reinterpret_cast< HiddenSimpleClass* >(SimpleClass::getInstance())->DoSomething();
return 0;
}



If this is really not what you are trying to accomplish, then you may have a bigger problem on your hands and a DLL may not be the proper approach. I hope this helps...

ZaneX

Share this post


Link to post
Share on other sites

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