Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Calling DLL from QM
#1
Hi Gintaras,

I've defined a DLL in C++ with the following header:

Macro Macro108
Code:
Copy      Help
// Math.h

#ifdef MATH_EXPORTS
#define MATH_API __declspec(dllexport)
#else
#define MATH_API __declspec(dllimport)
#endif

namespace Math
{
,// This class is exported from the Math.dll
,class MathFuncs
,{
,,public:
,,// Returns a + b
,,static MATH_API double Add(double a, double b);
,,
,,// Returns a - b
,,static MATH_API double Subtract(double a, double b);
,,
,,// Returns a * b
,,static MATH_API double Multiply(double a, double b);
,,
,,// Returns a / b
,,// Throws const std::invalid_argument& if b is 0
,,static MATH_API double Divide(double a, double b);
,};
}
What is the proper syntax to call it using QM?

Note: the DLL file name is "Math.dll"
#2
Exported class function names will be decorated. Open your dll file with depends.exe and copy the decorated name. QM code could be:
Macro Macro2345
Code:
Copy      Help
dll "$qm$\math.dll" [?Add@Math@@YANNN@Z]double'Math_Add double'a double'b
out Math_Add(5.7 2)

To avoid decoration, export non-class functions. Use either .def file or extern "C".

Or use a COM interface, especially when want to export non-static class functions.
#3
Thank you very much. Now I know more about the decoration thing. On my machine it will look like this:

Macro Macro106
Code:
Copy      Help
dll "$my qm$\Dll\Math.dll" [?Add@MathFuncs@Math@@SANNN@Z]double'Math_Add double'a double'b
out Math_Add(8.7 2)
#4
Could you give me a simple example just for "Add" function using:
1/ extern "C"
2/ COM interface
#5
Macro Macro2345
Code:
Copy      Help
//Put this before a non-class function declaration and definition to export the function with __cdecl calling convention. It is the easiest way, don't need a .def file. Using Microsoft Visual C++.
#define EXPORTC extern "C" __declspec(dllexport)

namespace Math
{
,class MathFuncs
,{
,,public:
,,// Returns a + b
,,static double Add(double a, double b);
,};

,double MathFuncs::Add(double a, double b) { return a+b; }

EXPORTC
double Math_Add(double a, double b) { return MathFuncs::Add(a, b); }        
}

With COM interface more work. If don't need to export non-static class members, better use extern "C".
#6
To export static class or non-class functions also can be used this. But such functions can be used only in QM.
Macro Macro2345
Code:
Copy      Help
//Put this before a non-class function declaration and definition to export the function with __cdecl calling convention. It is the easiest way, don't need a .def file. Using Microsoft Visual C++.
#define EXPORTC extern "C" __declspec(dllexport)

namespace Math
{
,class MathFuncs
,{
,,public:
,,// Returns a + b
,,static double Add(double a, double b);
,,static double Sub(double a, double b);
,};

,double MathFuncs::Add(double a, double b) { return a+b; }
,double MathFuncs::Sub(double a, double b) { return a-b; }

,const int mathFunctions[]=
,{
,,(int)MathFuncs::Add,
,,(int)MathFuncs::Sub,
,};

EXPORTC
const int* Math_GetFunctions() { return mathFunctions; }
Macro Macro2345
Code:
Copy      Help
dll- "my.dll"
,int*Math_GetFunctions
,double'Math_Add double'a double'b
,double'Math_Sub double'a double'b

int+* mathFunctions
if !mathFunctions
,mathFunctions=Math_GetFunctions
,&Math_Add=mathFunctions[0]
,&Math_Sub=mathFunctions[1]

out Math_Add(5.7 2)
out Math_Sub(5.7 2)
#7
COM interface.
Macro Macro2345
Code:
Copy      Help
//Put this before a non-class function declaration and definition to export the function with __cdecl calling convention. It is the easiest way, don't need a .def file. Using Microsoft Visual C++.
#define EXPORTC extern "C" __declspec(dllexport)

//I use this C macro to implement IUnknown functions QueryInterface, AddRef and Release that support standard reference counting.
//Can be used in any class that implements a COM interface. Example: STANDARD_IUNKNOWN_METHODS(IMyInterface)
#define STANDARD_IUNKNOWN_METHODS(iface) \
STDMETHODIMP QueryInterface(REFIID iid, void** ppv)\
{\
,if(iid == IID_IUnknown || iid == IID_##iface) { m_cRef++; *ppv = this; return S_OK; }\
,else { *ppv = 0; return E_NOINTERFACE; }\
}\
STDMETHODIMP_(ULONG) AddRef()\
{\
,return ++m_cRef;\
}\
STDMETHODIMP_(ULONG) Release()\
{\
,long ret=--m_cRef;\
,if(!ret) delete this;\
,return ret;\
}

namespace Math
{
,#define IID_IMathFuncs __uuidof(IMathFuncs)
,__interface __declspec(uuid("1DD0DD58-59C7-4308-93B8-40EEDEDE2415")) //replace this with your generated GUID
,IMathFuncs :public IUnknown
,{
,,STDMETHODIMP Add(double a, double b, double& R);
,,STDMETHODIMP Sub(double a, double b, double& R);
,};

,class MathFuncs :public IMathFuncs
,{
,,long m_cRef;
,,public:
,,MathFuncs() { m_cRef=1; }
#pragma region virtual_impl
,,STANDARD_IUNKNOWN_METHODS(IMathFuncs)
,,// Returns a + b
,,STDMETHODIMP Add(double a, double b, double& R);
,,STDMETHODIMP Sub(double a, double b, double& R);
#pragma endregion
,};

,STDMETHODIMP MathFuncs::Add(double a, double b, double& R) { R=a+b; return 0; }
,STDMETHODIMP MathFuncs::Sub(double a, double b, double& R) { R=a-b; return 0; }

EXPORTC
const IMathFuncs* Math_CreateObject() { return new MathFuncs; }

}
Macro Macro2345
Code:
Copy      Help
interface# IMathFuncs :IUnknown
,double'Add(double'a double'b)
,double'Sub(double'a double'b)
,{1DD0DD58-59C7-4308-93B8-40EEDEDE2415}

dll- "my.dll" IMathFuncs'Math_CreateObject

IMathFuncs m=Math_CreateObject
out m.Add(5.7 2)
out m.Sub(5.7 2)
#8
Thanks a lot for your samples and explanations.
I found that the extern "C" is simpler to use than the COM interface method.
The COM interface is "way beyond" my knowledge :-)
But it's interesting to see that it could be done by using it.

So far I've succeeded with the extern "C" method but with the COM interface I still have errors for the keywords:
"IUnknown" = error not a class or struct name
"STDMETHODIMP" = error identifier STDMETHODIMP is undefined

1/ Do I miss any header file for "STDMETHODIMP"?

2/ What tool do you use to get this ID?:
#define IID_IMathFuncs __uuidof(IMathFuncs)
__interface __declspec(uuid("1DD0DD58-59C7-4308-93B8-40EEDEDE2415")) //replace this with your generated GUID
#9
1. I don't know what exactly header need to include. In my project is #include <windows.h> and many others.
2. In Visual Studio menu Tools -> Create GUID. Or in QM: _s.Guid; out _s
#10
After I add "windows.h" to my header file, I could compile your COM interface sample.
And run the macro 2345 to test it, it works perfectly!
Thank you very much for your wonderful support!
Cheers!


Forum Jump:


Users browsing this thread: 1 Guest(s)