Legend:
Library
Module
Module type
Parameter
Class
Class type
Defining OCaml COM class objects
COM classes can be implemented in any DkSDK host platform.
The module ComClassBuilder lets you write classes in OCaml and register them so they can be accessed from any other DkSDK FFI platform (ex. DkSDK FFI Java).
Usage
Here is a minimal example that registers a COM class object:
open DkSDKFFIOCaml_Std
open ComStandardSchema.Make (ComMessage.C)
open Com.MakeClassBuilder (ComMessage.C)
let com = Com.create_c ()
let create_object return args =
let number = Reader.Si32.(i1_get (of_message args)) in
return (New
(Printf.sprintf
"instance constructed with create_object(args = %ld)"
number))
let ask ~self return args =
let question = Reader.St.(i1_get (of_message args)) in
let ret =
Printf.sprintf "I am an %s and I was asked: %s" self question
in
let bldr = Builder.St.(let r = init_root () in i1_set r ret; r) in
return (Capnp bldr)
register com ~classname:"Basic::Question::Taker"
[
class_method ~name:"create_object" ~f:create_object ();
instance_method ~name:"ask" ~f:ask ();
]
We can now use the Basic::Question::Taker COM class between programming languages linked into the same executable (ex. register a COM class in OCaml but use it in Java). DkSDK provides tools like DkSDK CMake to make it easy to link two programming languages into the same executable.
The coding patterns will look similar regardless of the programming language. Here we use the above registered COM class from OCaml itself:
open DkSDKFFIOCaml_Std
let com = Com.create_c ()
module BasicQuestionTaker = struct
open ComStandardSchema.Make (ComMessage.C)
let create com =
Com.borrow_class_until_finalized com "Basic::Question::Taker"
let method_create_object = Com.method_id "create_object"
let method_ask = Com.method_id "ask"
class questiontaker _clazz inst =
object
method ask question =
let args =
let open Builder.St in
let rw = init_root () in i1_set rw question; to_message rw
in
let ret_ptr =
Com.call_instance_method inst method_ask args
in
Reader.St.i1_get (Reader.of_pointer ret_ptr)
end
let new_questiontaker clazz number =
let args =
let open Builder.Si32 in
let r = init_root () in i1_set_int_exn r number; to_message r
in
Com.call_class_constructor
clazz method_create_object (new questiontaker clazz) args
end
let questiontaker_clazz = BasicQuestionTaker.create com
let questiontaker =
BasicQuestionTaker.new_questiontaker questiontaker_clazz 37
let () = print_endline (questiontaker#ask "What am I?")
(* I am an instance constructed with create_object(args = 37)
and I was asked: What am I? *)
The type of value that will be given to a return function, which is the API expected to be used by authors of DkSDK COM classes. The return value is either a single Cap n' Proto message of type Capnp 'builder, or a new instance of type New 'ret_inst. The type parameter 'inst is the type of the generic instance object whose method was called.
register com ~classname ?class_fallback_dtor ?instance_fallback_dtor [component1; component2; ...] builds a class named classname from a builder and a list of one or more components, and registers it as a COM object within DkSDK FFI.
If instance_fallback_dtor is specified, it will be the destructor used for instances when an explicit instance destructor is not called.
If class_fallback_dtor is specified, it will be the destructor used for classes when an explicit class destructor is not called. Typically these class destructors are only called when OCaml is shutting down.
class_method ~name ~f () adds an class method named name that will execute f when it is called.
f return args must use return to return either a Cap n' Proto message or a new instance, as in let f return args = return (Msg (*...*)) or let f return args = return (New (*...*)).
If the return value is a New instance, the return value will be bound to self of any instance_method or instance_destructor invocation that uses the new instance.
class_destructor ~name ~f () adds an class destructor named name that will execute f when it is called.
The class destructors are registered with an OCaml at_exit handler, which will be invoked during a graceful OCaml shutdown. However, there is no guarantee of a graceful OCaml shutdown, so class destructors are not guaranteed to be called.
instance_method ~name ~f () adds an instance method named name and will execute f ~self return args when it is called.
f ~self return args must use return to return either a Cap n' Proto message or a new instance, as in let f ~self return args = return (Msg (*...*)) or let f ~self return args = return (New (*...*)).
If the return value is a New instance, the return value will be bound to self of any instance_method or instance_destructor invocation that uses the new instance.