Discussion:
Win32 questions
Joshua Kordani
2014-10-15 20:02:07 UTC
Permalink
Greetings all. I am attempting to play with the FFI features of ccl,
and I've come up with this code snippet that I'd like some feedback on.

http://paste.lisp.org/display/144054

according to the win32 api, the function that I call will return 0 on
error and nonzero on success. In this case, this function is used to
request various bits of data about a given windows volume, and so all of
the arguments are optional. arguments are set to defaults with null
pointers, and the ones that the user would like filled are passed in
pointers that I imagine are already allocated for the given type of data.

In my annotation i changed the with-mactprs macro to the %stack-block
macro, I guess I didn't really realize that I'm allocating foreign
memory, or memory that foreign code will write to that I setup is
considered foreign memory, and then I guess the %stack-block macro is
the right thing here. Any feedback would be welcome!
--
Joshua Kordani
LSA Autonomy
Gary Byers
2014-10-16 04:18:19 UTC
Permalink
To digress (hopefully very briefly): lisp objects are dynamically
typed; "foreign objects" generally aren't. "Lisp memory" contains lisp
objects and is managed by a lisp-aware GC; "foreign memory" doesn't
contain lisp objects and is not generally of interest to the GC. C
(and other foreign code) operates on foreign objects in foreign memory
and Lisp code operates on lisp objects in lisp memory, and the twain
only meets in a few places (foriegn function calls and callbacks) in
CCL. There are a few ways of allocating and managing foreign memory
from Lisp code in CCL and of storing and accessing foreign values in
foreign memory; threre is (very intentionally) no way of going in the
other direction in CCL. Some of those ways of allocating foreign
memory allocate it on a stack. Hopefully, that's more than enough of a
digression ...


Using %STACK-BLOCK (as your annotation does) is more correct, but I'd
vote for using
RLET. (All of these things are fairly low-level, but RLET does a
little more for you.)

Recall that a MACPTR is a lisp object that encapsulates some absolute
address. WITH-MACPTRS will bind a set of variables to a set of MACPTR
objects and declares that those variable bindings have dynamic extent
(and therefore the MACPTRs which are the initial values of those
variables can be stack-allocated.) A MACPTR is a few dozem bytes at
most, but code which allocates those small lisp objects on a lisp stack
may CG less frequently than code that allocated them in the lisp heap.
The original code bound SN to a NULL pointer and passed the value of
that null pointer to the foreign fuinction; that's no different than
the other arguments where an explicit null pointer is used.

Your annocation used (%STACK-BLOCK ((SN 32)) ...) That will allocate
32 bytes on a foreign stack and bind SN to a MACPTR to the address of
that memory. If the foreign function call returns with no error, you
could get the value that the function stored there by something like

(%get-unsigned-long sn ; I'm assuming that a DWORD is a 32-bit
unsigned integer

If you don't remember how big a DWORD is (but do remember how to
capitalize it), you could also use RLET and PREF here.

(rlet ((sn #>DWORD))
...
(pref sn #>DWORD))

In C, you might have just said

DWORD sn;

and that's more succinct but it's exactly what the RLET is doing.
Post by Joshua Kordani
Greetings all. I am attempting to play with the FFI features of ccl,
and I've come up with this code snippet that I'd like some feedback on.
http://paste.lisp.org/display/144054
according to the win32 api, the function that I call will return 0 on
error and nonzero on success. In this case, this function is used to
request various bits of data about a given windows volume, and so all
of the arguments are optional. arguments are set to defaults with
null pointers, and the ones that the user would like filled are
passed in pointers that I imagine are already allocated for the given
type of data.
In my annotation i changed the with-mactprs macro to the %stack-block
macro, I guess I didn't really realize that I'm allocating foreign
memory, or memory that foreign code will write to that I setup is
considered foreign memory, and then I guess the %stack-block macro is
the right thing here. Any feedback would be welcome!
--
Joshua Kordani
LSA Autonomy
------quoted attachment------
Post by Joshua Kordani
_______________________________________________
Openmcl-devel mailing list
https://lists.clozure.com/mailman/listinfo/openmcl-devel
Joshua Kordani
2014-10-16 15:17:13 UTC
Permalink
Post by Gary Byers
To digress (hopefully very briefly): lisp objects are dynamically
typed; "foreign objects" generally aren't. "Lisp memory" contains
lisp objects and is managed by a lisp-aware GC; "foreign memory"
doesn't contain lisp objects and is not generally of interest to the
GC. C (and other foreign code) operates on foreign objects in foreign
memory and Lisp code operates on lisp objects in lisp memory, and the
twain only meets in a few places (foriegn function calls and
callbacks) in CCL. There are a few ways of allocating and managing
foreign memory from Lisp code in CCL and of storing and accessing
foreign values in foreign memory; threre is (very intentionally) no
way of going in the other direction in CCL. Some of those ways of
allocating foreign memory allocate it on a stack. Hopefully, that's
more than enough of a digression ...
Using %STACK-BLOCK (as your annotation does) is more correct, but I'd
vote for using
RLET. (All of these things are fairly low-level, but RLET does a
little more for you.)
Recall that a MACPTR is a lisp object that encapsulates some absolute
address. WITH-MACPTRS will bind a set of variables to a set of MACPTR
objects and declares that those variable bindings have dynamic extent
(and therefore the MACPTRs which are the initial values of those
variables can be stack-allocated.) A MACPTR is a few dozem bytes at
most, but code which allocates those small lisp objects on a lisp
stack may CG less frequently than code that allocated them in the lisp
heap. The original code bound SN to a NULL pointer and passed the
value of that null pointer to the foreign fuinction; that's no
different than the other arguments where an explicit null pointer is
used.
Your annocation used (%STACK-BLOCK ((SN 32)) ...) That will allocate
32 bytes on a foreign stack and bind SN to a MACPTR to the address of
that memory. If the foreign function call returns with no error, you
could get the value that the function stored there by something like
(%get-unsigned-long sn ; I'm assuming that a DWORD is a 32-bit
unsigned integer
If you don't remember how big a DWORD is (but do remember how to
capitalize it), you could also use RLET and PREF here.
(rlet ((sn #>DWORD))
...
(pref sn #>DWORD))
In C, you might have just said
DWORD sn;
and that's more succinct but it's exactly what the RLET is doing.
Thank you!! I will look into these more.


Joshua Kordani
LSA Autonomy

Loading...