How to Use a Class in Dll

How to use a class in DLL?

If you use run time dynamic linking (uses LoadLibrary to load the dll) you cannot access the class directly, you need to declare a interface for your class and create a function that returns a instance of this class, like this:

class ISDLConsole
{
public:
virtual void getInfo(int,int) = 0;
virtual void initConsole(char*, char*, SDL_Surface*, int, int, int) = 0;
virtual void sendMsg(char*,int, SDL_Surface*) = 0;
virtual void cls(SDL_Surface*) = 0;
};

class SDLConsole: public ISDLConsole
{
//rest of the code
};

__declspec(dllexport) ISDLConsole *Create()
{
return new SDLConsole();
}

Otherwise, if you link the dll during load time, just use the information provided by icecrime: http://msdn.microsoft.com/en-us/library/a90k134d.aspx

using a class defined in a c++ dll in c# code

There is no way to directly use a C++ class in C# code. You can use PInvoke in an indirect fashion to access your type.

The basic pattern is that for every member function in class Foo, create an associated non-member function which calls into the member function.

class Foo {
public:
int Bar();
};
extern "C" Foo* Foo_Create() { return new Foo(); }
extern "C" int Foo_Bar(Foo* pFoo) { return pFoo->Bar(); }
extern "C" void Foo_Delete(Foo* pFoo) { delete pFoo; }

Now it's a matter of PInvoking these methods into your C# code

[DllImport("Foo.dll")]
public static extern IntPtr Foo_Create();

[DllImport("Foo.dll")]
public static extern int Foo_Bar(IntPtr value);

[DllImport("Foo.dll")]
public static extern void Foo_Delete(IntPtr value);

The downside is you'll have an awkward IntPtr to pass around but it's a somewhat simple matter to create a C# wrapper class around this pointer to create a more usable model.

Even if you don't own this code, you can create another DLL which wraps the original DLL and provides a small PInvoke layer.

Access class in dll?

Take the following steps to access the method in library (dll), MSDN

  • Right click the references folder in your form project add click add reference select the project or folder of dll.
  • Include the namespace of the dll in your class (Form) suppose you have namespace yourcomapany.communication then use using to include namespace to access classes in it.

    using yourcomapany.communication;

C++ | DLL / EXE - How to call another class method from exported class?

You need to add __declspec(dllexport) to every class and function you want to be available outside of your dll, you don't need to mark methods as long as the containing class is exported.

Note in classes the declspec goes between class and the class name:

class __declspec(dllexport) Exported
{
};

You'll also need a macro defined which switches your headers between __declspec(dllexport) and __declspec(dllimport) depending on whether you are building your dll or exe, e.g.:

#ifdef BUILDING_MYDLL
#define MYDLL_EXPORT __declspec(dllexport)
#else
#define MYDLL_EXPORT __declspec(dllimport)
#endif

class MYDLL_EXPORT Exported
{
};

How to create an object from a DLL file in c++ at runtime?

If you can't use load-time binding you should use a pattern with a factory. The factory creates an instance of an object that implements an interface. The interface is a abstract class that can be used in the consumer.

Change your header file like this:

class ITrial
{
public:
virtual void test() = 0;
};

class Trial : ITrial
{
public:
Trial();
virtual void test() override;
};

// declare a function name that can be easily found with GetProcAdress.
extern "C" TRIALSHARED_API ITrial* CreateTrial();
typedef ITrial* (*PFN_Factory)();

Edit: The class ITrial is the interface to the functionality. You define a contract between the implementation and the consumer of the DLL. Only members that are defined here can be accessed. The DLL defines a class that is inherited from the interface class as the implementing class. The implementing class can have any additional member as it needs.
Edit end.

The header file must not include the __declspec(dllexport). The macro TRIALSHARED_EXPORT should be defined using conditional compilation.

#ifdef TRIAL_EXPORTS // defined only in the exporting DLL project
#define TRIALSHARED_API __declspec(dllexport)
#else
#define TRIALSHARED_API __declspec(dllimport)
#endif

Add to your Trial implementation:

ITrial* CreateTrial()
{
return new Trial;
}

Change your main function:

int main()
{
auto here=LoadLibrary(L"C:\\Users\\vinay\\Documents\\qt c++\\build-trial-Desktop_Qt_5_12_0_MinGW_64_bit-Debug\\debug\\trial.dll");
if(!here) {
cout<<"could not load the lib"<<std::endl;
return 1;
}
auto factory = reinterpret_cast<PFN_Factory>(GetProcAddress(here, "CreateTrial"));
if (!factory) {
cout<<"could not find factory"<<std::endl;
return 1;
}
auto pTrial = factory();
if (!pTrial) {
cout<<"factory failed"<<std::endl;
return 1;
}
pTrial->test();
delete pTrial;
}

The error handling is a bit clumsy. Change it as you need.

make c++ class in a native dll to use in C#

Having done this a bunch of times, the easiest way to do this is to write a C++/CLI wrapper to your existing classes. The reason being that P/Invoke works best on calls that are strictly C functions and not methods in a C++ class. In your example, how would you call operator new for the class that you specify?

If you can write this as a C++/CLI dll, then what you get is something that looks like this:

public ref class CliHuman {
public:
CliHuman() : _human(new Human()) { }
~CliHuman() { delete _human; }
protected:
!CliHuman() { delete _human; }
public:
void DoPee() { _human->Do_Pee(); }
private:
Human *_human;
};

Now, you might not have the freedom to do this. In this case, your best bet is to think about what it would take to expose a C API of your C++ object. For example:

extern "C" {

void *HumanCreate() { return (void *)new Human(); }
void HumanDestroy(void *p) { Human *h = (Human *)h; delete h; }
void HumanDoPee(void *p) { Human *h = (Human *)h; h->Pee(); }

};

You can P/Invoke into these wrappers very easily.

From an engineering standpoint, you would never want to do this ever since calling .NET code could pass in any arbitrary IntPtr. In my code, I like to do something like this:

#define kHumanMagic 0xbeefbeef;

typedef struct {
int magic;
Human *human;
} t_human;

static void *AllocateHuman()
{
t_human *h = (t_human *)malloc(sizeof(t_human));
if (!h) return 0;
h->magic = kHumanMagic;
h->human = new Human();
return h;
}

static void FreeHuman(void *p) /* p has been verified */
{
if (!p) return;
t_human *h = (t_human)p;
delete h->human;
h->human = 0;
h->magic = 0;
free(h);
}

static Human *HumanFromPtr(void *p)
{
if (!p) return 0;
t_human *h = (t_human *)p;
if (h->magic != kHumanMagic) return 0;
return h->human;
}
void *HumanCreate() { return AllocateHuman(); }
void HumanDestroy(void *p)
{
Human *h = HumanFromPtr(p);
if (h) {
FreeHuman(p);
}
else { /* error handling */ }
}
void HumanPee(void *p)
{
Human *h = HumanFromPtr(p);
if (h) h->Do_Pee();
else { /* error handling */ }
}

What you can see that I've done is create a light wrapper on top of the class that lets me verify that what comes in is more likely to be a correct pointer to what we want. The safety is likely not for your clients but for you - if you have to wrap a ton of classes, this will be more likely to catch errors in your code where you use one wrapper in place of another.

In my code base, we have found it especially useful to have a structure where we build a static library with the low-level code and the C-ish API on top of it then link that into a C++/CLI project that calls it (although I suppose to could P/Invoke into it from C# as well) instead of having the C++/CLI directly wrap the C++. The reason is that (to our surprise), all the low-level code which was using STL, was having the STL implementations done in CLI rather than in x86 or x64. This meant that supposedly low-level code that was iterating over STL collections would do something like 4n CLI transitions. By isolating the code, we worked around that quite well.

Putting classes in a DLL?

It is not possible to get a Class/Instance from a DLL.
Instead of the class you can hand over an interface to the class.
Below you find a simple example

// The Interface-Deklaration for Main and DLL
unit StringFunctions_IntfU;

interface

type
IStringFunctions = interface
['{240B567B-E619-48E4-8CDA-F6A722F44A71}']
function CopyStr( const AStr : WideString; Index, Count : Integer ) : WideString;
end;

implementation

end.

The simple DLL

library StringFunctions;

uses
StringFunctions_IntfU; // use Interface-Deklaration

{$R *.res}

type
TStringFunctions = class( TInterfacedObject, IStringFunctions )
protected
function CopyStr( const AStr : WideString; Index : Integer; Count : Integer ) : WideString;
end;

{ TStringFunctions }

function TStringFunctions.CopyStr( const AStr : WideString; Index, Count : Integer ) : WideString;
begin
Result := Copy( AStr, Index, Count );
end;

function GetStringFunctions : IStringFunctions; stdcall; export;
begin
Result := TStringFunctions.Create;
end;

exports
GetStringFunctions;

begin
end.

And now the simple Main Program

uses
StringFunctions_IntfU; // use Interface-Deklaration

// Static link to external function
function GetStringFunctions : IStringFunctions; stdcall; external 'StringFunctions.dll' name 'GetStringFunctions';

procedure TMainView.Button1Click( Sender : TObject );
begin
Label1.Caption := GetStringFunctions.CopyStr( Edit1.Text, 1, 5 );
end;

How can you import a public member from dll

Use dllexport to export your functions in a dll:

extern "C" __declspec(dllexport) bool void set_values (int,int);

You can also use dumpbin to generate definition file

dumpbin /EXPORTS tryDLL.dll > tryDLL.def

And then use lib.exe to build the .lib file which will work with your dll file:

lib /def:try.def /out:trydll.lib

Once properly exported, you can copy the DLL file in your application folder and include the directory and the lib file ( or use #pragma) into your project. Your exported class and function definitions should be declared in a header file, which still needs to be included in your project. That assured, your member function can be called like in any other ordinary program. You can access static member variables and constants declared in your dll declarations.



Related Topics



Leave a reply



Submit