Next Previous Contents

6.4 Implementing Haskell COM servers

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.


Next Previous Contents