If you're using GHC, you can also use HaskellDirect to help you create COM components/servers implemented in Haskell. This section explains the steps you need to follow when generating a Haskell COM component.
As always, the starting point is the specification of the component's
interfaces in IDL. Notice that if your component provides an
IDispatch interface to make it possible/easy to use the
component from within a scripting language such as
JavaScript, HaskellDirect provides you with an option
of how to implement the IDispatch wrapper. It can either
generate code which uses the system-provided type-library marshaller,
or use a Haskell-only solution. If you choose to go the type-library
route, you will need to express the IDispatch interface
as follows:
[ ... , oleautomation ]
interface IA : IUnknown { ... };
[ ..., odl, oleautomation ]
dispinterface DA { interface IA; };
i.e., using interface IA : IDispatch {...}; will not
work as expected.
Having specified the interfaces, the next step is to generate the proxy and the skeleton code for your component:
ihc -fcom MyComponent.idl -s --skeleton
which will generate two Haskell files, MyComponentProxy.hs
and MyComponent.hs. The latter contains the skeletal
implementation of the methods that your component implements, while
the former provides the proxy code which takes care of
wrapping up your methods behind a COM-callable interface.
The next step is to fill in the skeleton code with your implementation
of the component. Once done, compile up MyComponent.hs
followed by MyComponentProxy.hs.
With that out of the way, you now have to decide how to package your component. HaskellDirect's COM libraries provides support for building an in-proc server (i.e., in DLL form) or a local-proc server (i.e., in EXE form.)
If you go with the DLL option, you will need to copy two files
from the HaskellDirect's lib directory into your project directory,
ComDllMain.lhs and dll_stub.c, and compile these up.
Finally, you will need to supply a Main module, which
configures the name of the component etc.:
module Main(main, comComponents) where
import MyComponentProxy
import ComDll
comComponents :: [ ComponentInfo ]
comComponents =
[ hasTypeLib $
withComponentName "A Component I Prepared Earlier" $
withProgID "MyComponent.1" $
withVerIndepProgID "MyComponent" $
componentInfo
]
main = putStrLn "In Main"
(The Main.main isn't ever used, but GHC insist that there
is one.]
Once the Main module has been successfully compiled, build the DLL by following the instructions provided in Section Linking Haskell COM DLLs
The HaskellDirect distribution comes with a couple of examples of
Haskell COM servers, examples/comserv shows how to build
and package up an in-proc server.
If you instead want to provide a local-proc COM server in EXE form,
things are a little simpler. You simply need to supply a Main
module which starts up your server.
module Main(main) where
import MyComponentProxy
import ExeServer
main :: IO ()
main = do
runExeServer MyComponentProxy.componentInfo
For more information on what the various libraries used in this section provides, please consult Section Support libraries.