
Calling an non-DLL external function
Udo
Quote:
> Is there a possibility to call an external function when just the
> pointer to the function is known?
Indeed. Its easiest if you know the prototype of the method in advance, and
slightly harder if you want to construct the call completely dynamically.
See the attached for some examples.
Regards
Blair
------------
Object subclass: #FunctionPointerEg
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
classInstanceVariableNames: ''!
FunctionPointerEg guid: (GUID fromString:
'{67561145-D803-4B5E-9B96-9175EFCB4F48}')!
FunctionPointerEg comment: 'Invoking a function at a known address -
function prototype statically known.
FunctionPointerEg new example1
Same again, but copying the method in case we want to call the same function
at multiple addresses:
FunctionPointerEg new example2
Same again but dynamically constructed external call method (built with the
compiler).
FunctionPointerEg new example3
Other dynamic techniques would be to choose an existing ExternalMethod to
use as a template, then modify a copy of it to create the desired function
description, or building an ExternalMethod entirely from scratch. These are
left as an exercise for the reader.
'!
!FunctionPointerEg categoriesForClass: !Unclassified! !
!FunctionPointerEg methodsFor!
beep: anInteger dwDuration: dwDuration
<stdcall: bool Beep dword dword>
^self invalidCall!
example1
| method |
method := (self class compiledMethodAt: #beep:dwDuration:).
method descriptorLiteral dwordAtOffset: 0 put: (KernelLibrary default
getProcAddress: 'Beep').
300 to: 600 by: 100 do: [:i | self beep: i dwDuration: 100]
!
example2
| method |
method := (self class compiledMethodAt: #beep:dwDuration:) deepCopy.
method descriptorLiteral dwordAtOffset: 0 put: (KernelLibrary default
getProcAddress: 'Beep').
600 to: 300 by: -100 do: [:i | self beep: i dwDuration: 100]
!
example3
"The easiest way to build an ExternalMethod dynamically is to get the
compiler to do it"
| methodSource method |
"Somehow we've constructed this string based on information we have about
the
number and types of the arguments, etc"
methodSource := 'i: i j: j <stdcall: bool _ dword dword>'.
method := Compiler compile: methodSource in: Object.
"Set the function pointer"
method descriptorLiteral dwordAtOffset: 0 put: (KernelLibrary default
getProcAddress: 'Beep').
(300 to: 600 by: 100), (600 to: 300 by: -100) do: [:i | method value: self
withArguments: (Array with: i with: 100)]
!
initialize
| call |
call := (self class compiledMethodAt: #beep:dwDuration:).
call descriptorLiteral dwordAtOffset: 0 put: (KernelLibrary default
getProcAddress: 'Beep').
! !
!FunctionPointerEg categoriesFor:
#beep:dwDuration:!*-primitives!*-unclassified!public! !
!FunctionPointerEg categoriesFor: #example1!examples!public! !
!FunctionPointerEg categoriesFor: #example2!examples!public! !
!FunctionPointerEg categoriesFor: #example3!examples!public! !
!FunctionPointerEg categoriesFor: #initialize!initializing!public! !
!FunctionPointerEg class methodsFor!
new
^super new initialize! !
!FunctionPointerEg class categoriesFor: #new!instance creation!public! !