Next Previous Contents

4.8 COM specific options

Since one of HaskellDirect's goals is to support the integration of Haskell with COM, it has got some options specific for the COM backend:

-fno-gen-binary-interface

When generating stubs that has to work with HaskellScript, non-Automation interfaces are not of interest, due to the fact that they currently cannot be handled directly. This option causes the compiler to ignore such interfaces, emitting just a message informing the user what's happened.

This option is of less use now that HDirect is capable of generating Hugs stubs to binary interfaces.

-fuse-dispids

For Automation compatible interfaces, method invocation is either done by referring to the method by name (the default) or by method id (specified using the id() attribute.) Going via method ids (or, dispids, using Automation lingo) is quicker as it saves performing the method name to identifier mapping each time the method is invoked. If you want to do this, -fuse-dispids is your friend.

-fkeep-hresult

Methods of a COM interface return an HRESULT to indicate the success or otherwise of the method invocation. The HaskellDirect generated stubs will by default look at this status code to determine whether to flag an exception or not.

To disable this inspection of the HRESULT an instead have it returned back along with the other results of the method, use -fkeep-hresult.

-fcoalesce-methods

When working with Automation interfaces, you'll sometimes find that methods of different interfaces have the same name and take the same list of parameters (modulo the interface pointer, of course.) The -fcoalesce-methods option combines together the stubs for isomorphic methods into one. For example,

[...]
interface IA : IDispatch {
   HRESULT lookup([in,string]BSTR name, [out]int* res);
   ...
};
    
[...]
interface IB : IDispatch {
   HRESULT lookup([in,string]BSTR name, [out]int* res);
   ...
};

With -fcoalesce-methods enabled, only one lookup stub will be generated:

lookup :: Int -> IDispatch a -> IO Int

Notice that this isn't entirely typesafe, since lookup can now be applied to any IDispatch interface pointer, not just IA and IB ones. If you do, a Haskell IO exception will be raised, telling you that method lookup isn't supported by that particular object.

In some cases, this trade-off between type safety and size of the generated stub code is worth considering, since method coalescion can drastically reduce the amount of stubs you need to generate for particular components / object models.

-fsubtyped-interface-pointers

This option is now enabled by default, so you really shouldn't have to use it any longer. It causes interface pointers to be represented in Haskell in a way that allows us to easily reuse the method stubs of the interface(s) we're inheriting from. To demonstrate, suppose you have the following two interfaces:

[...]
interface IPlus : IUnknown {
   HRESULT add([in]int i1, [in]int i2,[out]int* res);
};
[...]
interface IPlusMinus : IPlus {
   HRESULT sub([in]int i1, [in]int i2,[out]int* res);
};

i.e., you can perform the add operation on an instance of the IPlus interface, while instances of IPlusMinus also allow you to perform the sub operation. Having to generate one add stub for IPlus and IPlusMinus would be tedious in the extreme, so let's avoid this by representing the interface pointers themselves as follows:

type IPlusMinus  a = IPlus (PlusMinus a)
data IPlusMinus_ a = IPlusMinus_

type IPlus a  = IUnknown (Plus a)
data IPlus_ a = IPlus_

A value of type IPlus is a COM interface pointer that, at least, supports the methods of the IPlus interface. The IPlusMinus interface is of IPlus's ilk, being defined as a synonym for IPlus. Expanding out the type synonyms is illuminating:

type IPlusMinus a = IPlus (IPlusMinus_ a)
                  = IUnknown (IPlus_ (IPlusMinus_ a))

i.e., by parameterising the interface pointers over a type that describes the extension of the interface, the relationship between IPlus and IPlusMinus interfaces is maintained at the Haskell type level, with IUnknown's type parameter envoding the interface inheritance chain.

The dummy types Plus and PlusMinus are needed to let the type checker do it's job of catching illegal uses of interface pointers, e.g., the application of sub to an interface pointer that just implements IPlus.

Since IPlusMinus is a synonym for IPlus, the generated stub for add can now also be used by IPlusMinus:

add :: Int -> Int -> IPlus a -> IO Int
sub :: Int -> Int -> IPlusMinus a -> IO Int

-funparamed-interface-pointers

Use a representation of interface types that isn't parameterised over the sub type, but a mere type synonym to the interface type it inherits from, e.g.,

type IPlus = IUnknown
type IPlusMinus = IPlus

-fignore-dispinterfaces

For a COM component that support more than one IUnknown interface, there's a problem when it comes to providing an Automation interface to the same functionality, since supporting multiple IDispatch interfaces is tricky.

One solution to the problem is to define one big 'dispinterface' containing all the methods of the various binary COM interfaces. Not particularly pretty, but that's how several IDL specs solve this problem.

When generating client bindings, you're not really interested in both the IDispatch interface to a method and the 'binary' one. In case it's the latter, -fignore-dispinterfaces causes the compiler to simply overlook dispinterfaces when generating stubs. Sometimes useful.

The -fignore-dispinterfaces option is the inverse of -fno-gen-binary-interface option.

-fsort-defns

The compiler currently makes the assumption that the definition of an IDL entity preceedes any of its uses (as does MIDL and other IDL compilers). So, if you feed it input where this isn't the case, use -fsort-defns to dependency sort the declarations before processing them further.

With a little bit of work this assumption could be dropped, but until that time, -fsort-defns is your friend.

Note: if you're feeding HaskellDirect input you got through the use of Microsoft's OleView utility, -fsort-defns is required, as that tool does not sort the IDL it generates. To avoid such troubles alltogether, simply avoid OleView and have HaskellDirect process the type libraries for you directly.

-fdual-vtbl

Dual interfaces can either be invoked via the vtbl (i.e., 'binary' invocation) or through IDispatch and Invoke(). The option -fdual-vtbl instructs the compiler to generate stubs that perform method invocation via the vtbl (the default is the other way around.)

-fno-expand-inherited

For interfaces that inherit from a non-'builtin' interface (i.e., IUnknown and IDispatch), don't expand the contents of the inherited interface when compiling the interface that inherits. Experimental, not really of use with the current interface pointer representation.

-fprefix-interface-name

Prepend the name of the interface to the names of the Haskell method stubs. This is one way to fight namespace clashes, the default scheme used is to make method names unique within one Haskell module by appending a unique number to methods with the same (Haskell) name, i.e., if there's two methods called next, the second will be renamed to next0. -fprefix-interface-name offers an alternative to this scheme, mapping next0 to iEnumFoo_Next instead.

-fno-overload-variant

By default, argument occurrences of the Automation VARIANT type will cause HaskellDirect to overload the corresponding Haskell method argument using the Automation.Variant type class.

To turn this behaviour off, use -fno-overload-variant to have VARIANT map to Automation.VARIANT instead; a pointer to an externally-allocated VARIANT value.

-fno-enum-magic

The COM specification specifies the assumed `shape' of enumeration interfaces, i.e., interfaces that lets you enumerate the elements present in a collection. The only difference between two enumeration interfaces is the type of elements that they allows the client to enumerate over. So, providing a shared set of stubs for these enumeration methods makes good sense, parameterising the stubs on how to unpack the enumeration values the interface methods return.

HaskellDirect will by default generate code that makes use of these parameterised enumeration stubs, but should you for one reason or another not want to use these, use -fno-enum-magic to turn this default off.

-fno-mangle-interface-names

Turn off interface name mangling for interface dummy types. Experimental and not a particularly useful option.

--tlb

HaskellDirect supports the reading of type libraries on Win32 platforms. Use --tlb to try to open the input files on the command line as type libraries.

-ftreat-importlibs-as-imports

A deprecated option, which instead of trying to import type information from a type library when it encounters a importlib() statement, will try to import from the corresponding IDL (source) file instead.

This option was of some use before HaskellDirect supported the reading of type libraries - of little use now.

-fanon-typelib

For Haskell COM components that implement the interface IDispatch, the compiler will generate a type library to aid in its implementation. This type library is normally accessed by looking up its registered GUID, but in the event you don't want to have the type library be registered, use -fanon-typelib.

-fmaybe-optional-params

For Automation clients, the compiler's default behaviour when encountering optional arguments is to use overloading. For example,

 [...]
 interface IA : IDispatch {
   HRESULT meth([in,optional]int i);
 };

gives

  meth :: Variant a => a0 -> IA a -> IO ()

the option -fmaybe-optional-params uses a Maybe instead, giving you

  meth :: Maybe Int -> IA a -> IO ()

-fignore-importlibs

If any importlib() declarations are encountered in the IDL input, just ignore them.

-fignore-methods-upto=Name

Instead of factoring them out, some (generated) IDL input may prefix all interfaces with a set of identical methods, i.e., the interfaces contain:

interface IA : IUnknown { HRESULT m1 (); .... }
interface IB : IUnknown { HRESULT m1 (); .... }

rather than

interface IBase : IUnknown { HRESULT m1 (); }
interface IA : IBase { HRESULT m1 (); .... }
interface IB : IBase { HRESULT m1 (); .... }

To avoid generating N stubs for m1, use -fignore-methods-upto=m1.

-fshow-idl-in-comments

Put the IDL in comments next to the Haskell code that it generated.

-fappend-interface-short-name

Within each Haskell module generated, if there's a name clash between two method names, they're disambiguated by appending the number 1 to the second one. The -fappend-interface-short-name option takes a different approach at disambiguating methods by appending the upper case letters of their corresponding interface. For example,

interface IOleFoo : IUnknown {
  HRESULT meth();
};
interface IOleBar : IUnknown {
  HRESULT meth();
};

The stub for the method IOleBar.meth is named methOB in the generated Haskell code.

-fno-gen-variant-instance

For each enumeration type, the default is to generate an instance of the Automation.Variant class it. Use -fno-gen-variant-instance to turn this off.

-fexplicit-i-pointer

For Automation clients, the generated stubs does not give the interface pointer explicitly as an argument. To have it do so, use -fexplicit-i-pointer.

-fno-library-ids

For each library declaration, we generate a Haskell definition of its LIBID. To disable this, use -fno-library-ids.

-foverload-variant

When generating Automation client stubs, the default is to overload arguments that have type VARIANT. To enable this behaviour for non-Automation clients, use -foverload-variant.

-fuse-std-dispatch

When generating proxy code for Haskell COM servers, the default is to use the system-supplied, type library marshaller to implement IDispatch. A simpler, Haskell-only implementation of IDispatch is also supported by the HaskellDirect COM libraries. To use this instead, use -fuse-std-dispatch.


Next Previous Contents