Calling API functions dynamically?

U

Usenet User

I need to be able to call the same API function from VB, which will
reside in different DLLs. While all of the functions have the same
signature and name, DLL file names are not known at compile time.
Therefore, my assumption that using Declare statement or DllImport
attribute is NOT an option in such a case.

I can use LoadLibrary() and GetProcAddress() from Kernel32 to get the
addreses, but is there a way to actually call an API method by its
address from VB? Or can anyone suggest anything else?

TIA!
 
T

Thorsten Albers

Usenet User said:
I need to be able to call the same API function from VB, which will
reside in different DLLs. While all of the functions have the same
signature and name, DLL file names are not known at compile time.
Therefore, my assumption that using Declare statement or DllImport
attribute is NOT an option in such a case.

I can use LoadLibrary() and GetProcAddress() from Kernel32 to get the
addreses, but is there a way to actually call an API method by its
address from VB? Or can anyone suggest anything else?

I can think of two ways:

a) Build and use a standard DLL (C(++)) which redirects the function call
to the respective DLL.

b) Add a declare statement with a - more or less :) - unique library file
name. Then, before calling the library function, make a copy of the
original library and name it with this unique file name. The copy of the
library of course has to be located somewhere where the OS can find it.

--
 
C

Chris Dunaway

Usenet said:
I need to be able to call the same API function from VB, which will
reside in different DLLs. While all of the functions have the same

Why would you do this? Are you trying to create some sort of "plugin"
architecture? Do you have control over the .dll you are trying to call
or are they 3rd party?

Perhaps you could create a single class in which you pass the name of
the .dll as a string and then inside the class, call the api method
based on that string.

Good luck
 
T

Tom Esh

I need to be able to call the same API function from VB, which will
reside in different DLLs. While all of the functions have the same
signature and name, DLL file names are not known at compile time.
Therefore, my assumption that using Declare statement or DllImport
attribute is NOT an option in such a case.

I can use LoadLibrary() and GetProcAddress() from Kernel32 to get the
addreses, but is there a way to actually call an API method by its
address from VB? Or can anyone suggest anything else?

Another way (hack) is to use the function address obtained with
GetProcAddress with CallWindowProc. The catch here (big catch) is the
function being called needs to take exactly 4 32-bit args or you'll
hose the stack. There are ways around that limitation (using
~assembly~ opcodes to restore the stack). Matt Currland's book
"Advanced VB6" covers the technique. Definitely not for the feint of
heart - pure voodoo IMO <g>


-Tom
MVP - Visual Basic
(please post replies to the newsgroup)
 
M

mr_unreliable

hi Usenet,

There are two pre-programmed, pre-digested solutions to this.

1. My favorite, written by Arkadiy Olovyannikov, and called:
"Call API functions by Name, without Declare", can be found
on the freevbcode website:

http://www.freevbcode.com/ShowCode.Asp?ID=1863

2. However, the api newsgroupies here may be expected to heap
disrespect on Arkadiy's code. They have asserted that the only
"real" legitimate appropriate code to do this was written by
Matthew Curland. There is an article by Curland on this subject,
originally published in "Visual Basic Programmer's Journal",
and now available on the web, entitled: "Call Function Pointers".

http://www.fawcette.com/archives/listissue.asp?pubID=1&MagIssueId=265#

Also, if you have $40 in spare change, (and you can still find it)
you may purchase Curland's book "Advanced Visual Basic 6", and you
will find the same "Call Function Pointers" code in there.

cheers, jw
____________________________________________________________

You got questions? WE GOT ANSWERS!!! ..(but,
no guarantee the answers will be applicable to the questions)
 
R

Randy Birch

Matt's book still appears to be available through
http://service.bfast.com/bfast/click?bfmid=2181&sourceid=251059&bfpid=0201707128&bfmtype=book

--

Randy Birch
MS MVP Visual Basic
http://vbnet.mvps.org/

Please reply to the newsgroups so all can participate.




hi Usenet,

There are two pre-programmed, pre-digested solutions to this.

1. My favorite, written by Arkadiy Olovyannikov, and called:
"Call API functions by Name, without Declare", can be found
on the freevbcode website:

http://www.freevbcode.com/ShowCode.Asp?ID=1863

2. However, the api newsgroupies here may be expected to heap
disrespect on Arkadiy's code. They have asserted that the only
"real" legitimate appropriate code to do this was written by
Matthew Curland. There is an article by Curland on this subject,
originally published in "Visual Basic Programmer's Journal",
and now available on the web, entitled: "Call Function Pointers".

http://www.fawcette.com/archives/listissue.asp?pubID=1&MagIssueId=265#

Also, if you have $40 in spare change, (and you can still find it)
you may purchase Curland's book "Advanced Visual Basic 6", and you
will find the same "Call Function Pointers" code in there.

cheers, jw
____________________________________________________________

You got questions? WE GOT ANSWERS!!! ..(but,
no guarantee the answers will be applicable to the questions)
 
M

Michael C

mr_unreliable said:
hi Usenet,

There are two pre-programmed, pre-digested solutions to this.

1. My favorite, written by Arkadiy Olovyannikov, and called:
"Call API functions by Name, without Declare", can be found
on the freevbcode website:

http://www.freevbcode.com/ShowCode.Asp?ID=1863

I downloaded this code and much to my suprise it was a modification to some
code I put on the net many years ago. I don't see anything wrong with the
method except it could be optimised not to build the assembly code for each
call in this function:

Public Function CallFunction(ParamArray FuncParams()) As Long
Dim i As Long
If m_lpFn = 0 Then
MsgBox "Function not defined!", vbCritical, "Call function error"
Exit Function
End If
ReDim m_abCode(0)
ReDim m_lParameters(UBound(FuncParams) + 1)
ReDim m_abCode(18 + 32 + 6 * UBound(m_lParameters))
For i = 1 To UBound(m_lParameters)
m_lParameters(i) = CLng(FuncParams(i - 1))
Next i
CallFunction = CallWindowProc(PrepareCode, 0, 0, 0, 0)
m_lpFn = 0
End Function
2. However, the api newsgroupies here may be expected to heap
disrespect on Arkadiy's code. They have asserted that the only
"real" legitimate appropriate code to do this was written by
Matthew Curland. There is an article by Curland on this subject,
originally published in "Visual Basic Programmer's Journal",
and now available on the web, entitled: "Call Function Pointers".

I don't see how matthew's method would be any less hacky. I can't see it
though as that page requires a login.

Michael
 
M

Michael C

Usenet User said:
I need to be able to call the same API function from VB, which will
reside in different DLLs. While all of the functions have the same
signature and name, DLL file names are not known at compile time.
Therefore, my assumption that using Declare statement or DllImport
attribute is NOT an option in such a case.

I can use LoadLibrary() and GetProcAddress() from Kernel32 to get the
addreses, but is there a way to actually call an API method by its
address from VB? Or can anyone suggest anything else?

If your dlls have the same name but diff dir just use LoadLibrary and
FreeLibrary with the standard vb6 declare, eg

Declare Function Whatever Lib "MyDLL" ....
Sub DoIt()
lib = LoadLibrary("C:\abc\MyDll.dll")
WhatEver(....)
FreeLibrary(lib)
End Sub

because a library of name MyDLL is already loaded vb6 will just use that.
Just make sure you match the no of loadlib calls with freelib and don't call
your function without calling LoadLibrary at least once somewhere in code.

Michael
 
M

Michael C

Karl E. Peterson said:

Ok, I had a look at his code. It shoves assembly code into a currency
variable and does pretty much the same thing but requires the extra
complexity of creating and referencing a typelib (presumably a new typelib
for each different call signature). It also has the reduced flexibility of
not being able to call cdecl functions. Matt has a bad habit of
overcomplicating things. But then again karl, don't let logic get in your
way. :)

Michael
 
S

Stefan Berglund

in said:
Ok, I had a look at his code. It shoves assembly code into a currency
variable and does pretty much the same thing but requires the extra
complexity of creating and referencing a typelib (presumably a new typelib
for each different call signature). It also has the reduced flexibility of
not being able to call cdecl functions. Matt has a bad habit of
overcomplicating things. But then again karl, don't let logic get in your
way. :)

Michael

You must be one of those irreverent dot net freaks that think you can
easily discredit someone who spent years building their reputation
simply by virtue of vomiting your spew.

m$' latest piece of f**k doesn't qualify you to make those allegations
but I must admit you do provide great comic relief for those who are
more discerning in what they read and believe.

Thanks for the laughs hyena.
 
M

Michael C

Stefan Berglund said:
You must be one of those irreverent dot net freaks that think you can
easily discredit someone who spent years building their reputation
simply by virtue of vomiting your spew.

m$' latest piece of f**k doesn't qualify you to make those allegations
but I must admit you do provide great comic relief for those who are
more discerning in what they read and believe.

Thanks for the laughs hyena.

What on earth are you talking about. I did not mention dot net at all in
this thread. Was the link karly posted something about dot net?

I was commenting on matt curland's method of calling a function pointer in
vb6.

Michael
 
A

Anthony Jones

mr_unreliable said:
hi Usenet,

There are two pre-programmed, pre-digested solutions to this.

1. My favorite, written by Arkadiy Olovyannikov, and called:
"Call API functions by Name, without Declare", can be found
on the freevbcode website:

http://www.freevbcode.com/ShowCode.Asp?ID=1863

2. However, the api newsgroupies here may be expected to heap
disrespect on Arkadiy's code. They have asserted that the only
"real" legitimate appropriate code to do this was written by
Matthew Curland. There is an article by Curland on this subject,
originally published in "Visual Basic Programmer's Journal",
and now available on the web, entitled: "Call Function Pointers".

http://www.fawcette.com/archives/listissue.asp?pubID=1&MagIssueId=265#

Also, if you have $40 in spare change, (and you can still find it)
you may purchase Curland's book "Advanced Visual Basic 6", and you
will find the same "Call Function Pointers" code in there.

Both of these approaches have a serious draw back. They require that a
small piece of assembly be used to thunk the call. Problem is that this
little piece of assembly resides in memory allocated as data. Back when
these approaches were originally written that wasn't a problem. Today
though a machine running with DEP turned on will kill any process trying to
do this.
 
J

Jim Mack

Anthony said:
Both of these approaches have a serious draw back. They require that
a small piece of assembly be used to thunk the call. Problem is that
this little piece of assembly resides in memory allocated as data.
Back when these approaches were originally written that wasn't a
problem. Today though a machine running with DEP turned on will kill
any process trying to do this.

I usually hesitate to offer only a commercial solution, but all the others have been mentioned, and as you note they have drawbacks.

While it isn't free, our Stamina library has among its almost 500 assembly-language functions, DxCall and DxCallByName. These can call arbitrary stdcall, pascal and cdecl functions having up to 16 parameters (and a return value) of any mix of variant-safe types. It also deals with conversions between Unicode and Ansi as needed.

DxCall is best for repeated calls to the same function, or for calling VB functions (internal callbacks, for example) since it takes an address or function pointer. DxCallByName is simpler for one-off calls, since it takes a DLL name and function name as parameters and deals with LoadLibrary etc internally.

Stamina is for VB32 and VBA only, not .net
 
K

Karl E. Peterson

Michael said:
Ok, I had a look at his code. It shoves assembly code into a currency
variable and does pretty much the same thing but requires the extra
complexity of creating and referencing a typelib (presumably a new
typelib for each different call signature). It also has the reduced
flexibility of not being able to call cdecl functions. Matt has a bad
habit of overcomplicating things. But then again karl, don't let
logic get in your way. :)

You seem quite confused. But then again, what else is new?

I was only attempting to help you view what you saw to be off-limits.

No moral or technical judgements were offered.
 
M

mr_unreliable

Right. But microsoft's advice in this situation is to
allocate memory with both data and execute privileges
turned on, and put your assembly in that.

Fortunately, this is not hard to do, and with that
modification Arkadiy Olovyannikov's code will work
successfully on xp -- even with dep turned on --
until microsoft comes up with some other hurdle
to jump over.

cheers, jw
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top