Interface function implementation in a DLL

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
KeldorKatarn
Posts: 6
Joined: Sun Feb 25, 2007 7:30 pm

Interface function implementation in a DLL

Post by KeldorKatarn »

Hi,

I am trying to implement an interface function in a DLL that will enable me to access everything else in the DLL like it is done in the Irrlicht engine with its createDevice() function.

I am basically trying to have a function like this:

MY_API MyClass* GetPointer();

MY_API MyClass* GetPointer()
{
return new MyClass();
}

I am using this for MY_API:

#ifdef DO_EXPORTS
#define MY_API __declspec(dllexport)
#else
#define MY_API __declspec(dllimport)
#endif


Now this function is exported well but when I try to use it in a test
program I get linker errors when I try to
access the member functions of this class by doing something like this:

#include "Interface.h" // Declaration of the imported function declaration
of GetPointer()
#include "MyClass.h" // Header of the class, not with

int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PTSTR cmdLine,
int cmdShow)
{
MyClass* pointer = GetPointer();

pointer->MemberFunction();

delete pointer;

return 0;
}

I keep getting the LNK2019: unresolved external symbol error for both member
functions (the member and the destructor).

I know I do not export the class itself, but I do include the header, and
Irrlicht engine also just exports this one interface function that delivers
a pointer and accesses everything else through that pointer.

(Doesn't work if I return the object by value either)

The declarations of the member functions should be read in the header and the implementation be read at runtime in the dll.. why do I get a linker error here. The constructor works if called from within the exported
function, why does the rest not work for the already constructed object?
It works in Irrlicht and I have looked at that source a hundred times and I
don't see what I do different.

Is there a trick to this I missed? How do I get this to work? Any
recommendations/hints?
This is my first try at writing a DLL and I kinda need this to work before I
can continue implementing further stuff in this DLL.

Thank you in advance for any information you can give me on how you made this work.

Greetings

KeldorKatarn
monkeycracks
Posts: 1029
Joined: Thu Apr 06, 2006 12:45 am
Location: Tennesee, USA
Contact:

Post by monkeycracks »

I've been having the same problem unfortunately.
Hope someone can get around to answering this question..
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

Well, it sounds like the problem that you are running into is that you haven't defined the MyClass class in your dll/lib. Since the user of your dll is directly accessing MyClass that class has non-abstract functions declared, so those symbols must be exported.

There is quite a bit of difference between what you are doing and what Irrlicht is doing. You have a single concrete class MyClass that the application must know about. You have no interface class at all. I would think you'd have something like this...

Code: Select all

// Interface.h
#ifndef _INTERFACE_H_INCLUDED__
#define _INTERFACE_H_INCLUDED__

#ifdef DO_EXPORTS 
#define MY_API __declspec(dllexport) 
#else 
#define MY_API __declspec(dllimport) 
#endif 

// fwd decl.
class IMyClass;

MY_API IMyClass* GetClass();

#endif // _INTERFACE_H_INCLUDED__

// Interface.cpp
#include "Interface.h"
#include "CMyClass.h"

MY_API IMyClass* GetClass()
{
  return new CMyClass;
}

// IMyClass.h
#ifndef _I_MY_CLASS_H_INCLUDED__
#define _I_MY_CLASS_H_INCLUDED__

class IMyClass
{
public:
  // must be virtual because user gets pointer to base class and
  // is expected to delete it. this must be defined somewhere otherwise
  // there would be a linker error. we just define it inline.
  virtual ~IMyClass() {}

  // a method on this class. this method is made abstract so that derived
  // classes can provide a definition and this class does not have to be
  // exported [it still defines no symbols other than the dtor]
  virtual void MemberFunction() = 0;

  // if you feel you must, you could define a method inline. this way you
  // don't have to export anything. normally it is bad design to define a
  // method on an interface class.
};

#endif // _I_MY_CLASS_H_INCLUDED__

// CMyClass.h
#ifdef  _C_MY_CLASS_H_INCLUDED__
#define _C_MY_CLASS_H_INCLUDED__

class CMylass : public IMyClass
{
public:
  virtual void MemberFunction();
};

#endif // _C_MY_CLASS_H_INCLUDED__

// CMyClass.cpp
#include "CMyClass.h"
#include <stdio.h>

void
CMyClass::MemberFunction()
{
  printf("hello world\n");
}
While you're feeling your way around this, you should consider implementing a scheme so that the user doesn't directly call delete on memory that is allocated in your dll. Your CMyClass instance is allocated in the dll, but would be deleted in the executable. This can cause problems. It might be a good idea to do something similar to Irrlichts IUnknown for this reason.

Travis
KeldorKatarn
Posts: 6
Joined: Sun Feb 25, 2007 7:30 pm

Post by KeldorKatarn »

Duh! The virtual function table.. thanks.. that was the hint I needed.

About the rest you mentioned.. yes I was planning on deriving the final classes, and I was also planning on using a Singlenton implementation for most of them. But stupid as I was I wanted to try this DLL export thing (which I have never tried before) with a simple class and kept wondering why it didn't work. So it will only work for virtual functions because those are looked up. (Or for inline). Thanks very much.
I know what Irrlicht does with those interface classes, I just didn't realize this would influence the way things are imported from the DLL. As I said, I've never coded a DLL before. So thanks, that was the hint I needed. Now all this is making sense *g*
Post Reply