Link to home
Start Free TrialLog in
Avatar of griffitt
griffitt

asked on

Calling Functions in DLL's

I have a DLL written by another party which I cannot change.  It is called by a C++ application and is therfore designed with this in mind.  I now need to call the same function using VB6.

If I declare the 'raw' DLL and call it directly it causes the VB IDE to drop faster than if using the cross!  I therefore wrote a wrapper DLL using the 'standard call' convention in VC++6.

If I now try to declare the wrapper DLL it gives error 49 - bad DLL calling convention - and then the IDE falls over (but much more slowly!).

Has anyone any ideas about this?

Thanks.
Avatar of corvanderlinden
corvanderlinden

Did you use extern "C" in front of your function in the DLL?
How does your C declaration look
How does your VB declaration look

Avatar of griffitt

ASKER

Good point!  Not a huge amount of detail in the original question!

The 'raw' DLL is called as extern "C" from within the 'wrapper' DLL (and indeed when called from a Fortran program I use C_EXTERNAL).

The C declraration of the 'raw' DLL is:
extern "C" void thingy(long *mode,double levels[]);

The 'wrapper' DLL code is:
#include thingy.h //declaration as above.

void __stdcall wrapthingy(long mod, double lev[])
{
    thingy(mode,lev);
}

The 'thingy.def' file:
LIBRARY thingy

EXPORTS
WrapThingy=wrapthingy @1

In VB the declaration is:
Public Declare Sub DoThingy Lib "e:\apps32\libs\thingy.dll" Alias "WrapThingy" _
(ByRef mainmode As Long, ByRef sLev() As Double)

Did this help?
My Opinion: mod should be pointer

wrapthingy(long *mod, double lev[])

Call from VB
Call DoThingy(mainmode, sLev(0))

Keep me informed

OK I actually made a mistake in writing the previous comment!

The call in the 'wrapper' DLL

thingy(&mod,lev);

Also if I try:

Call DoThingy(mainmode, sLev(0))

in the VB I get a Type mismatch error!
In VB the declaration should then be:

Public Declare Sub DoThingy Lib "e:\apps32\libs\thingy.dll" Alias "WrapThingy" _
(ByVal mainmode As Long, ByRef sLev() As Double)

Then

Call DoThingy(mainmode, sLev)

Hope it helps!


I made that change and it still won't work although it now doesn't give the 'bad calling convention error' and it causes the VB IDE to drop as quickly as when calling the 'raw' DLL directly.

However the 'raw' DLL can be called successfully from both Fortran and C++ programs without a problem.  

I assume that the problem must therefore lie in the design of the 'wrapper' DLL.
Question:

How did you declare sLev in VB

Dim sLev(n) as double

Is the dimension (n) large enough?

Also try

extern "C" void __stdcall wrapthingy(long mod, double lev[])

and

extern "C" void __stdcall wrapthingy(long mod, double *lev)

(man, this is a tough one)
Question:

How did you declare sLev in VB

Dim sLev(n) as double

Is the dimension (n) large enough?

Also try

extern "C" void __stdcall wrapthingy(long mod, double lev[])

and

extern "C" void __stdcall wrapthingy(long mod, double *lev)

(man, this is a tough one)
The sLev array has 16 elements which is the same as in the 'raw' DLL function.

I also tried both the suggestions for the definition of the wrapthingy function but they don't make any difference.

I am also following developments on the "Passing VB arrays to VC++ DLL's" question.  I am now looking at redefining in structures for the call from VB to VC++ as well as following the suggestions here.

Thanks for your effort on this one - it is appreciated.
The only thing I can think of is following:

From VB you give mod to the wrapper ByValue
In the wrapper you give the address of mod to the C++ Dll
Here mod is changed. In fact you are changing VB's stack (mod)
VB still thinks it gave mod ByValue, and another is changing it's contents
I think maybe VB does not like that

Maybe as a last try you could do:

void __stdcall wrapthingy(long *mod, double lev[])
{
    thingy(mode,lev);
}


Public Declare Sub DoThingy Lib "e:\apps32\libs\thingy.dll" Alias "WrapThingy" _
(ByRef mainmode As Long, ByRef sLev() As Double)

Call DoThingy(mainmode, sLev)

This is all I can think of.

If you find a solution I would be pleased if you let me now

c.vanderlinden@artaker.com

Good luck!!!!!


ASKER CERTIFIED SOLUTION
Avatar of manojamin
manojamin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
OK, I seem to have sorted it out now!

The actual spec for the 'wrapper' DLL was fine as I had it at the start - the problem was the declaration and call in VB.

I will summarise the whole thing here for simplicity!

WRAPPER DLL:
thingy.h
extern "C" void thingy(long *mode,double levels[]);

thingy.cpp
#include thingy.h

void __stdcall wrapthingy(long mod, double lev[])
{
    thingy(mod,lev);
}

The 'thingy.def' file:
LIBRARY thingy

EXPORTS
WrapThingy=wrapthingy @1

All the above is how I started!

Now in VB:

The declaration:
Public Declare Sub DoThingy Lib "E:\somepath\thingy.dll" Alias WrapThingy(ByVal mode As Long, ByRef Lev As Double)

The call:
Call DoThingy(mode,Lev(0))

It appears that the 'trick' is to NOT declare the array argument as an array!

I think I will have to give the points to manojamin because it was as a result of reading the Microsoft article that I solved it (not that the article solved it explicitly!).  However I am grateful for all the effort put in by corvanderlinden.
Thanks for the article - I have posted a summary of the answer I devised as a comment.