By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,955 Members | 1,756 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,955 IT Pros & Developers. It's quick & easy.

Bad DLL calling convention

P: n/a
Made a C++ dll with MS VC6 and trying to call the dll from Excel VBA.

This is the code in the .cpp file:
#include "stdafx.h"
#include <string>
#include <math.h>

using namespace std;

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
//to compare case in-sensitive
//----------------------------
int CompareIgnoreCase(const string& s, const string& s2)
{
string::const_iterator p = s.begin(),
p2 = s2.begin();

while(p!= s.end() && p2!= s2.end()){
if(tolower(*p)!= tolower(*p2))return tolower(*p)< tolower(*p2) ? -1: 1;
++p; ++p2;
}
return s2.size()- s.size();
}
//round number n to d decimal points
//----------------------------------
double fround(double n, unsigned d)
{return floor(n * pow(10, d) + 0.5) / pow(10, d);}
double _stdcall Framingham2 (long Age,
long SysBP,
double TotChol,
double HDL,
string Sex,
string Diabetes,
string LVH,
string Smoke,
long Years = 10)
{
int x;
int btSex;
int btDiabetes;
int btLVH;
int btSmoke;
string sFEMALE = "FEMALE";
string sYES = "YES";
double dMu;
double dS;
double dU;
double dProb;

//exclude out of range input
//--------------------------
if ((Age < 35) ||
(Age > 75) ||
(SysBP < 50) ||
(SysBP > 300) ||
(TotChol < 1) ||
(TotChol > 30) ||
(HDL < 0.2) ||
(HDL > 10) ||
(Years > 10))
return 0;

x = CompareIgnoreCase(Sex,sFEMALE);
if (x == 0)
btSex = 1;
else
btSex = 0;

x = CompareIgnoreCase(Diabetes,sYES);
if (x == 0)
btDiabetes = 1;
else
btDiabetes = 0;

x = CompareIgnoreCase(LVH,sYES);
if (x == 0)
btLVH = 1;
else
btLVH = 0;

x = CompareIgnoreCase(Smoke,sYES);
if (x == 0)
btSmoke = 1;
else
btSmoke = 0;

dMu = 15.5305 +
28.4441 * btSex +
-1.4792 * log(Age) +
-14.4588 * log(Age) * btSex +
1.8515 * pow(log(Age), 2) * btSex +
-0.9119 * log(SysBP) +
-0.2767 * btSmoke +
-0.7181 * log(TotChol / HDL) +
-0.1759 * btDiabetes +
-0.1999 * btDiabetes * btSex +
-0.5865 * btLVH;

dS = exp(0.9145 + (-0.2784 * dMu));
dU = (log(Years) - dMu) / dS;
dProb = 1 - exp(-exp(dU));

return fround(dProb * 100,1);
}

I have included a .def file with this:

EXPORTS
Framingham2

It compiles (win32 release) nicely without any errors or warnings.
The function also shows nicely when I run DEPENDS.EXE.
I have checked the function in a C++ console app and that runs fine giving
the right
results. This is without input arguments though and with the values
hard-coded.

In Excel VBA I do this:

Option Explicit
Private Declare Function Framingham2 _
Lib "C:\Program Files\Microsoft Visual
Studio\MyProjects\Framingham\Release\Framingham.dl l" _
(ByVal Age As Long, _
ByVal SysBP As Long, _
ByVal TotChol As Double, _
ByVal HDL As Double, _
ByVal Sex As String, _
ByVal Diabetes As String, _
ByVal LVH As String, _
ByVal Smoke As String, _
ByVal Years As Long) As Double
Sub test()

MsgBox Framingham2(50, 140, 5.6, 1.6, "male", "no", "no", "no", 10)

End Sub

This compiles fine, but when I run Sub test() I get Run-time error 49: Badd
DLL calling convention.
I have tried altering the datatypes both in the VBA declaration and in the
..cpp file but no success.
I am completely new to this, so I am sure I have done something stupid
somewhere, but I just can't find it.
Thanks for any advice.
RBS

Apr 16 '06 #1
Share this Question
Share on Google+
6 Replies


P: n/a
RB Smissaert <ba***********@blueyonder.co.uk> wrote:
Made a C++ dll with MS VC6 and trying to call the dll from Excel VBA.
You are off-topic here, as you do not have a problem with C++, but
the your particular environment. Try comp.os.ms-windows.programmer.win32
instead.

I will answer anyway, see below for the off-topic-ness ;)
double _stdcall Framingham2 (long Age,
long SysBP,
double TotChol,
double HDL,
string Sex,
string Diabetes,
string LVH,
string Smoke,
long Years = 10) Private Declare Function Framingham2 _
Lib "C:\Program Files\Microsoft Visual
Studio\MyProjects\Framingham\Release\Framingham.dl l" _
(ByVal Age As Long, _
ByVal SysBP As Long, _
ByVal TotChol As Double, _
ByVal HDL As Double, _
ByVal Sex As String, _
ByVal Diabetes As String, _
ByVal LVH As String, _
ByVal Smoke As String, _
ByVal Years As Long) As Double
This compiles fine, but when I run Sub test() I get Run-time error
49: Badd DLL calling convention.
I have tried altering the datatypes both in the VBA declaration and
in the .cpp file but no success.


A 'string' in C++ is a C++ data type. This data-type has most
probably different representation than the VB string type, though they
effectivly hold the same information. Google for "passing C-strings to
VB" or similar. I know there was a KB article on MSDN showing how to
pass strings from VB to C Dll and back. If I remember correctly, you
have to change your function in the Dll to accept a 'char const*'
instead of 'string'. But you better look that up again.

Other than that, _stdcall should probably be __stdcall (two
underscores) .. not sure if that makes a difference tho.

hth
--
jb

(reply address in rot13, unscramble first)
Apr 16 '06 #2

P: n/a
Thanks for the quick reply.
Not sure I agree I am off topic here though.

I also had an inkling that doing:
#include <string>
and declaring as string in the .cpp was a bit too simple.

Will just find an example of a C++ dll that accepts
string arguments from VB and see how that is done.

RBS
"Jakob Bieling" <ar****************@rot13.com> wrote in message
news:e1*************@news.t-online.com...
RB Smissaert <ba***********@blueyonder.co.uk> wrote:
Made a C++ dll with MS VC6 and trying to call the dll from Excel VBA.


You are off-topic here, as you do not have a problem with C++, but the
your particular environment. Try comp.os.ms-windows.programmer.win32
instead.

I will answer anyway, see below for the off-topic-ness ;)
double _stdcall Framingham2 (long Age,
long SysBP,
double TotChol,
double HDL,
string Sex,
string Diabetes,
string LVH,
string Smoke,
long Years = 10)

Private Declare Function Framingham2 _
Lib "C:\Program Files\Microsoft Visual
Studio\MyProjects\Framingham\Release\Framingham.dl l" _
(ByVal Age As Long, _
ByVal SysBP As Long, _
ByVal TotChol As Double, _
ByVal HDL As Double, _
ByVal Sex As String, _
ByVal Diabetes As String, _
ByVal LVH As String, _
ByVal Smoke As String, _
ByVal Years As Long) As Double


This compiles fine, but when I run Sub test() I get Run-time error
49: Badd DLL calling convention.
I have tried altering the datatypes both in the VBA declaration and
in the .cpp file but no success.


A 'string' in C++ is a C++ data type. This data-type has most probably
different representation than the VB string type, though they effectivly
hold the same information. Google for "passing C-strings to VB" or
similar. I know there was a KB article on MSDN showing how to pass strings
from VB to C Dll and back. If I remember correctly, you have to change
your function in the Dll to accept a 'char const*' instead of 'string'.
But you better look that up again.

Other than that, _stdcall should probably be __stdcall (two
underscores) .. not sure if that makes a difference tho.

hth
--
jb

(reply address in rot13, unscramble first)


Apr 16 '06 #3

P: n/a
RB Smissaert <ba***********@blueyonder.co.uk> wrote:
Not sure I agree I am off topic here though.
Trust me, you are.

Neither Dlls, nor specific calling conventions are part of the
Standard C++ language. In other words, your code will not compile and
run on any other box unless it is running Windows. So your code is
platform specific, and thus leaving the realms of what is defined by
Standard C++, the topic of this group.
I also had an inkling that doing:
#include <string>
and declaring as string in the .cpp was a bit too simple.

Will just find an example of a C++ dll that accepts
string arguments from VB and see how that is done.


I checked my own code. Change your function like so

double __stdcall Framingham2 (long Age,
long SysBP,
double TotChol,
double HDL,
char const* Sex,
char const* Diabetes,
char const* LVH,
char const* Smoke,
long Years = 10)

And it should work. I know this can be tricky, so maybe there are
other things I have overlooked. In that case, please direct further
questions to comp.os.ms-windows.programmer.win32, as you will also get
better help for this problem there.

regards
--
jb

(reply address in rot13, unscramble first)
Apr 16 '06 #4

P: n/a
For somebody who thinks I am in the wrong group you have done a good
job in helping as you were absolutely right. Changing from string to
char const* made it all work nicely. Will just have to figure out now what
char const* exactlyt means/does and that will be it for now.
Also will have to test if this kind of dll actually is faster than running
this from VBA.
Ideally I think this should go in a .xll add-in but that would definitely be
off-topic.
Will post to the group you suggested next time if I have something similar.
Thanks again.

RBS

"Jakob Bieling" <ar****************@rot13.com> wrote in message
news:e1*************@news.t-online.com...
RB Smissaert <ba***********@blueyonder.co.uk> wrote:
Not sure I agree I am off topic here though.


Trust me, you are.

Neither Dlls, nor specific calling conventions are part of the Standard
C++ language. In other words, your code will not compile and run on any
other box unless it is running Windows. So your code is platform specific,
and thus leaving the realms of what is defined by Standard C++, the topic
of this group.
I also had an inkling that doing:
#include <string>
and declaring as string in the .cpp was a bit too simple.

Will just find an example of a C++ dll that accepts
string arguments from VB and see how that is done.


I checked my own code. Change your function like so

double __stdcall Framingham2 (long Age,
long SysBP,
double TotChol,
double HDL,
char const* Sex,
char const* Diabetes,
char const* LVH,
char const* Smoke,
long Years = 10)

And it should work. I know this can be tricky, so maybe there are other
things I have overlooked. In that case, please direct further questions to
comp.os.ms-windows.programmer.win32, as you will also get better help for
this problem there.

regards
--
jb

(reply address in rot13, unscramble first)


Apr 16 '06 #5

P: n/a
Just to say that putting this function in a regular C++ dll doesn't speed it
up that much. I got it about 20% faster.
Will now see if I can put this in an .xll, which I think might
be faster as it directly works with the Excel C API.

RBS

"RB Smissaert" <ba***********@blueyonder.co.uk> wrote in message
news:oH*********************@fe3.news.blueyonder.c o.uk...
Made a C++ dll with MS VC6 and trying to call the dll from Excel VBA.

This is the code in the .cpp file:
#include "stdafx.h"
#include <string>
#include <math.h>

using namespace std;

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
//to compare case in-sensitive
//----------------------------
int CompareIgnoreCase(const string& s, const string& s2)
{
string::const_iterator p = s.begin(),
p2 = s2.begin();

while(p!= s.end() && p2!= s2.end()){
if(tolower(*p)!= tolower(*p2))return tolower(*p)< tolower(*p2) ? -1: 1;
++p; ++p2;
}
return s2.size()- s.size();
}
//round number n to d decimal points
//----------------------------------
double fround(double n, unsigned d)
{return floor(n * pow(10, d) + 0.5) / pow(10, d);}
double _stdcall Framingham2 (long Age,
long SysBP,
double TotChol,
double HDL,
string Sex,
string Diabetes,
string LVH,
string Smoke,
long Years = 10)
{
int x;
int btSex;
int btDiabetes;
int btLVH;
int btSmoke;
string sFEMALE = "FEMALE";
string sYES = "YES";
double dMu;
double dS;
double dU;
double dProb;

//exclude out of range input
//--------------------------
if ((Age < 35) ||
(Age > 75) ||
(SysBP < 50) ||
(SysBP > 300) ||
(TotChol < 1) ||
(TotChol > 30) ||
(HDL < 0.2) ||
(HDL > 10) ||
(Years > 10))
return 0;

x = CompareIgnoreCase(Sex,sFEMALE);
if (x == 0)
btSex = 1;
else
btSex = 0;

x = CompareIgnoreCase(Diabetes,sYES);
if (x == 0)
btDiabetes = 1;
else
btDiabetes = 0;

x = CompareIgnoreCase(LVH,sYES);
if (x == 0)
btLVH = 1;
else
btLVH = 0;

x = CompareIgnoreCase(Smoke,sYES);
if (x == 0)
btSmoke = 1;
else
btSmoke = 0;

dMu = 15.5305 +
28.4441 * btSex +
-1.4792 * log(Age) +
-14.4588 * log(Age) * btSex +
1.8515 * pow(log(Age), 2) * btSex +
-0.9119 * log(SysBP) +
-0.2767 * btSmoke +
-0.7181 * log(TotChol / HDL) +
-0.1759 * btDiabetes +
-0.1999 * btDiabetes * btSex +
-0.5865 * btLVH;

dS = exp(0.9145 + (-0.2784 * dMu));
dU = (log(Years) - dMu) / dS;
dProb = 1 - exp(-exp(dU));

return fround(dProb * 100,1);
}

I have included a .def file with this:

EXPORTS
Framingham2

It compiles (win32 release) nicely without any errors or warnings.
The function also shows nicely when I run DEPENDS.EXE.
I have checked the function in a C++ console app and that runs fine giving
the right
results. This is without input arguments though and with the values
hard-coded.

In Excel VBA I do this:

Option Explicit
Private Declare Function Framingham2 _
Lib "C:\Program Files\Microsoft Visual
Studio\MyProjects\Framingham\Release\Framingham.dl l" _
(ByVal Age As Long, _
ByVal SysBP As Long, _
ByVal TotChol As Double, _
ByVal HDL As Double, _
ByVal Sex As String, _
ByVal Diabetes As String, _
ByVal LVH As String, _
ByVal Smoke As String, _
ByVal Years As Long) As Double
Sub test()

MsgBox Framingham2(50, 140, 5.6, 1.6, "male", "no", "no", "no", 10)

End Sub

This compiles fine, but when I run Sub test() I get Run-time error 49:
Badd DLL calling convention.
I have tried altering the datatypes both in the VBA declaration and in the
.cpp file but no success.
I am completely new to this, so I am sure I have done something stupid
somewhere, but I just can't find it.
Thanks for any advice.
RBS


Apr 16 '06 #6

P: n/a
OK, doing this in an .xll add-in is indeed much faster.
It timed it 30 times faster in a moderately complex
math function. This is compared with the VBA function.
Compared with the C++ dll it will be about 25 times faster.

RBS
"RB Smissaert" <ba***********@blueyonder.co.uk> wrote in message
news:Zc********************@fe3.news.blueyonder.co .uk...
Just to say that putting this function in a regular C++ dll doesn't speed
it up that much. I got it about 20% faster.
Will now see if I can put this in an .xll, which I think might
be faster as it directly works with the Excel C API.

RBS

"RB Smissaert" <ba***********@blueyonder.co.uk> wrote in message
news:oH*********************@fe3.news.blueyonder.c o.uk...
Made a C++ dll with MS VC6 and trying to call the dll from Excel VBA.

This is the code in the .cpp file:
#include "stdafx.h"
#include <string>
#include <math.h>

using namespace std;

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
//to compare case in-sensitive
//----------------------------
int CompareIgnoreCase(const string& s, const string& s2)
{
string::const_iterator p = s.begin(),
p2 = s2.begin();

while(p!= s.end() && p2!= s2.end()){
if(tolower(*p)!= tolower(*p2))return tolower(*p)< tolower(*p2) ? -1:
1;
++p; ++p2;
}
return s2.size()- s.size();
}
//round number n to d decimal points
//----------------------------------
double fround(double n, unsigned d)
{return floor(n * pow(10, d) + 0.5) / pow(10, d);}
double _stdcall Framingham2 (long Age,
long SysBP,
double TotChol,
double HDL,
string Sex,
string Diabetes,
string LVH,
string Smoke,
long Years = 10)
{
int x;
int btSex;
int btDiabetes;
int btLVH;
int btSmoke;
string sFEMALE = "FEMALE";
string sYES = "YES";
double dMu;
double dS;
double dU;
double dProb;

//exclude out of range input
//--------------------------
if ((Age < 35) ||
(Age > 75) ||
(SysBP < 50) ||
(SysBP > 300) ||
(TotChol < 1) ||
(TotChol > 30) ||
(HDL < 0.2) ||
(HDL > 10) ||
(Years > 10))
return 0;

x = CompareIgnoreCase(Sex,sFEMALE);
if (x == 0)
btSex = 1;
else
btSex = 0;

x = CompareIgnoreCase(Diabetes,sYES);
if (x == 0)
btDiabetes = 1;
else
btDiabetes = 0;

x = CompareIgnoreCase(LVH,sYES);
if (x == 0)
btLVH = 1;
else
btLVH = 0;

x = CompareIgnoreCase(Smoke,sYES);
if (x == 0)
btSmoke = 1;
else
btSmoke = 0;

dMu = 15.5305 +
28.4441 * btSex +
-1.4792 * log(Age) +
-14.4588 * log(Age) * btSex +
1.8515 * pow(log(Age), 2) * btSex +
-0.9119 * log(SysBP) +
-0.2767 * btSmoke +
-0.7181 * log(TotChol / HDL) +
-0.1759 * btDiabetes +
-0.1999 * btDiabetes * btSex +
-0.5865 * btLVH;

dS = exp(0.9145 + (-0.2784 * dMu));
dU = (log(Years) - dMu) / dS;
dProb = 1 - exp(-exp(dU));

return fround(dProb * 100,1);
}

I have included a .def file with this:

EXPORTS
Framingham2

It compiles (win32 release) nicely without any errors or warnings.
The function also shows nicely when I run DEPENDS.EXE.
I have checked the function in a C++ console app and that runs fine
giving the right
results. This is without input arguments though and with the values
hard-coded.

In Excel VBA I do this:

Option Explicit
Private Declare Function Framingham2 _
Lib "C:\Program Files\Microsoft Visual
Studio\MyProjects\Framingham\Release\Framingham.dl l" _
(ByVal Age As Long, _
ByVal SysBP As Long, _
ByVal TotChol As Double, _
ByVal HDL As Double, _
ByVal Sex As String, _
ByVal Diabetes As String, _
ByVal LVH As String, _
ByVal Smoke As String, _
ByVal Years As Long) As Double
Sub test()

MsgBox Framingham2(50, 140, 5.6, 1.6, "male", "no", "no", "no", 10)

End Sub

This compiles fine, but when I run Sub test() I get Run-time error 49:
Badd DLL calling convention.
I have tried altering the datatypes both in the VBA declaration and in
the .cpp file but no success.
I am completely new to this, so I am sure I have done something stupid
somewhere, but I just can't find it.
Thanks for any advice.
RBS


Apr 17 '06 #7

This discussion thread is closed

Replies have been disabled for this discussion.