Posts: 133
Threads: 15
Joined: Jun 2014
Hi Gintaras,
I've defined a DLL in C++ with the following header:
Macro Macro108
// 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"
Posts: 12,055
Threads: 140
Joined: Dec 2002
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
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.
Posts: 133
Threads: 15
Joined: Jun 2014
Thank you very much. Now I know more about the decoration thing. On my machine it will look like this:
Macro Macro106
dll "$my qm$\Dll\Math.dll" [?Add@MathFuncs@Math@@SANNN@Z]double'Math_Add double'a double'b
out Math_Add(8.7 2)
Posts: 133
Threads: 15
Joined: Jun 2014
Could you give me a simple example just for "Add" function using:
1/ extern "C"
2/ COM interface
Posts: 12,055
Threads: 140
Joined: Dec 2002
Macro Macro2345
//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".
Posts: 12,055
Threads: 140
Joined: Dec 2002
To export static class or non-class functions also can be used this. But such functions can be used only in QM.
Macro Macro2345
//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
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)
Posts: 12,055
Threads: 140
Joined: Dec 2002
COM interface.
Macro Macro2345
//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
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)
Posts: 133
Threads: 15
Joined: Jun 2014
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
Posts: 12,055
Threads: 140
Joined: Dec 2002
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
Posts: 133
Threads: 15
Joined: Jun 2014
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!
|