Can't use a C++ class from a DLL

Artie apple2000 at mail.ru
Sun Oct 28 12:52:01 PDT 2012


I have a DLL with a C++ class and a factory function that creates 
it. The aim is to load the DLL, get an instance of the class and 
use it.

The interface of the DLL is as follows:
-----------------
class IBank
{
     public:
         virtual const char* APIENTRY getLastError() = 0;
         virtual const char* APIENTRY getDetail(char* detail) = 0;
         virtual const bool APIENTRY deposit(unsigned long number, 
double amount) = 0;
         virtual const bool APIENTRY withdraw(unsigned long 
number, double amount) = 0;
         virtual const double APIENTRY getBalance(unsigned long 
number) = 0;
         virtual const bool APIENTRY transfer(unsigned long 
numberFrom, IBank* bankTo, unsigned long numberTo, double amount) 
= 0;
         virtual const bool APIENTRY transferAccept(IBank* 
bankFrom, unsigned long numberTo, double amount) = 0;
};
-----------------

I've followed the instructions given at dlang.org to interface to 
C/C++ code but got no success. If I use extern(C++) at the place 
in D code where extern declaration is required I get an access 
violation when calling any method. On the other hand, if I use 
extern(Windows, C or Pascal) I can call a method successfully, 
except that I get wrong return value.

The D interface is declared as follows:
-----------------
extern (Windows) interface IBank
{
	const char* getLastError();
	const char* getDetail(char* detail);
	const bool deposit(uint number, double amount);
	const bool withdraw(uint number, double amount);
	const double getBalance(uint number);
	const bool transfer(uint numberFrom, IBank* bankTo, uint 
numberTo, double amount);
	const bool transferAccept(IBank* bankFrom, uint numberTo, double 
amount);
}

export extern (C) IBank Get();
-----------------


And the main program in D that uses the DLL:
-----------------
module main;

import std.stdio;
import core.runtime;
import core.sys.windows.windows;
import std.string;
import std.conv;

import ibank;

int main()
{
	alias extern(C) IBank function() getBankInstance;
	FARPROC pDllFunctionVBank, pDllFunctionSberbank;

	// Load DLL file
	void* handleVBank = Runtime.loadLibrary("vbank.dll");
	void* handleSberbank = Runtime.loadLibrary("sberbank.dll");

	if ( (handleVBank is null) || (handleSberbank is null) )
	{
		writeln("Couldn't find necessary DLL files");
		return 1;
	}

	getBankInstance get1 = cast(getBankInstance) 
GetProcAddress(handleVBank, "Get".toStringz);
	getBankInstance get2 = cast(getBankInstance) 
GetProcAddress(handleSberbank, "Get".toStringz);

	if ( get1 is null || get2 is null )
	{
		writeln("Couldn't load factory functions");
		return 2;
	}

	getBankInstance get;
	IBank vbank = (*get1)();
	IBank sberbank = get2();


	uint sbnum = 100500;
	uint vbnum = 128500;

	writeln("You have an account in Sberbank (100500)");
	auto balance = sberbank.getBalance(sbnum);
	writefln("getBalance(%d) = %s", sbnum, balance);
	bool res = sberbank.withdraw(sbnum, 500.0);
	writefln("withdraw(%d, %f) = %s", sbnum, 500.0, res);
	writeln("You got it!");
...
-----------------

The output I get is (in case I use extern (Windows, C or Pascal)):
-----------------
You have an account in Sberbank (100500)
getBalance(100500) = -nan
got into GenericBank::getBalance() // this is an output from a 
method called inside the DLL
account number = 100500 // inside the DLL
balance is 1100 // inside the DLL
withdraw(100500, 500.000000) = false
You got it!
-----------------


More information about the Digitalmars-d mailing list