This monstrosity, believe it or not, almost does what I want, except for the section between lambda and case lambda. The structure of the list is not right. So there is definitely something I'm missing, some recursion or piece of knowledge about macros. I think I should be using 'with-syntax' or something. Any pointers in the right direction would be appreciated.
(trace-define-syntax (foreign-struct x)
(syntax-case x ()
((_ name (var1 type1) (var2 type2) ...)
#`(begin
(define-ftype name (struct (var1 type1) (var2 type2) ...))
(define #,(datum->syntax #'name (scheme-name (syntax->datum #'name)))
(lambda (var1 var2 ...)
(let ((ptr (make-ftype-pointer name (foreign-alloc (ftype-sizeof name)))))
#,(let lp ((v1 #'var1) (v2 #'(var2 ...)))
(if (null? v2)
#`(ftype-set! name (#,v1) ptr val)
(cons #`(ftype-set! name (#,v1) ptr val)
(lp (car v2) (cdr v2)))))
(case-lambda
((var)
#,(append
(cons* #'case #'var
(let lp ((v1 #'var1) (v2 #'(var2 ...)))
(if (null? v2)
(cons (append #`(#,v1)
#`((ftype-ref name (#,v1) ptr))) '())
(cons (append #`(#,v1)
#`((ftype-ref name (#,v1) ptr)))
(lp (car v2) (cdr v2))))))
#`((else (error 'name "bad arg" 'val)))))
((var val)
#,(append
(cons* #'case #'var
(let lp ((v1 #'var1) (v2 #'(var2 ...)))
(if (null? v2)
(cons (append #`(#,v1)
#`((ftype-set! name (#,v1) ptr val))) '())
(cons (append #`(#,v1)
#`((ftype-set! name (#,v1) ptr val)))
(lp (car v2) (cdr v2))))))
#`((else (error 'name "bad arg" 'val)))))
(() ptr)))))))))