cnuernber / dtype-next

A Clojure library designed to aid in the implementation of high performance algorithms and systems.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How do you pass a null pointer to a C function or include one in a struct?

emassey0135 opened this issue · comments

I am currently trying to create a GUI application in Clojure using the Win32 API. I am using tech.v3.datatype.ffi, and compiling the program with GraalVM Native Image. Many functions in the Win32 API have parameters that can either be a pointer to an object or NULL, which means that the object passed by this parameter is not necessary for that particular invocation. An example of this is the MessageBoxW function, whose first parameter can be a pointer to a window handle to set the parent window of the message box, or NULL, which makes the message box have no parent window. However, when I try to create a null pointer and pass it as the first parameter to MessageBoxW, it fails when I run the executable created by native-image. I used the following code:

(ns my-ns (:require
[tech.v3.datatype.ffi :as dt-ffi])
(:gen-class))
(defn string->utf-16 [str]
(dt-ffi/string->c str {:encoding :utf-16LE}))
(def windows-api (dt-ffi/define-library-interface 
{:MessageBoxW {:rettype :int32 :argtypes [['hWnd :pointer] ['lpText :pointer] ['lpCaption :pointer] ['uType :int32]]}}))
(def mb-ok 0)
(defn -main [& args]
(MessageBoxW (tech.v3.datatype.ffi.Pointer. 0) (string->utf-16 "This is an FFI call.") (string->utf-16 "Alert") mb-ok))

Compiling this code succeeds, but I get the following error when I run the generated executable: "Exception in thread "main" java.lang.Exception: Pointer value is zero!". When I replace [hWnd :pointer] in the library declaration with ['hWnd :size-t], and (tech.v3.datatype.ffi.Pointer. 0) with 0 in the function call, it works, but this means I cannot call MessageBoxW with a window handle if I need to later. How do I define a function that can either take a pointer to an object or a null pointer? There are also a lot of structs that have values like this.

Bold! I like it :-) - Use :pointer? in your function definition. This allows null pointers to pass through.

Thank you, that fixes the issue. However, maybe you should mention what the :pointer? type is used for somewhere in the documentation for tech.v3.datatype.ffi, perhaps under "Things to Consider", since that would make this information easy to find.

100% agreed.