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.
griffittAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

corvanderlindenCommented:
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

0
griffittAuthor Commented:
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?
0
corvanderlindenCommented:
My Opinion: mod should be pointer

wrapthingy(long *mod, double lev[])

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

Keep me informed

0
The Ultimate Tool Kit for Technolgy Solution Provi

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy for valuable how-to assets including sample agreements, checklists, flowcharts, and more!

griffittAuthor Commented:
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!
0
corvanderlindenCommented:
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!


0
griffittAuthor Commented:
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.
0
corvanderlindenCommented:
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)
0
corvanderlindenCommented:
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)
0
griffittAuthor Commented:
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.
0
corvanderlindenCommented:
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!!!!!


0
manojaminCommented:
Read this, It may help you...

I think all this is happening is because of the Passing Array from VB to C dll..

try to put log (file logs) in your WrapThingy function to see what vb is passing..


HOWTO: Write C DLLs and Call Them from Visual Basic

http://support.microsoft.com/support/kb/articles/Q106/5/53.asp

look for "Pointers to Arrays" section (also see all the detail and make sure your are doing it correctly...)
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
griffittAuthor Commented:
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.
0
griffittAuthor Commented:
Thanks for the article - I have posted a summary of the answer I devised as a comment.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.