packages feed

com-1.2.3: cbits/dllStub.c

/*
 * Entry points needed to implement a COM inproc server.
 * The C wrappers defined here delegate to (library) methods
 * implemented in Haskell.
 * 
 * Sigbjorn Finne, 1999
 */

#include <windows.h>
#include "comPrim.h"

/*
 * A Haskell in-proc server exposes a VTBL which mimics
 * the entry points that a self-registering inproc server
 * has to supply to the outside world.
 *
 */
typedef struct IComDll {
   void    (*dllUnload)();
   HRESULT (*dllCanUnloadNow)();
   HRESULT (*dllRegisterServer)();
   HRESULT (*dllUnregisterServer)();
   HRESULT (*dllGetClassObject)(CLSID* clsid, IID* iid,
			        void** ppv);
} ComDll;

ComDll* comDll = NULL;

extern ComDll* newComDll ( HANDLE hMod );

#if __GLASGOW_HASKELL__ >= 408
extern void startupHaskell (int argc, char* argv[], void* rootMod);
extern void* __stginit_ComDllMain;
extern void shutdownHaskell (void);
#else
extern void startupHaskell(int , char** );
extern void shutdownHaskell (void);
#endif

static char* args[] = { "ghcDll" };

BOOL
STDCALL
DllMain
   ( HANDLE hModule
   , DWORD reason
   , void* reserved
   )
{
  if (reason == DLL_PROCESS_ATTACH) {
      /* By now, the RTS DLL should have been hoisted in, but we need to start
         it up.
	 
	 Note: for ghc-4.08 and later, you need to give the main / 'root module'
	 of the Haskell module you want to start running. So, if this is something 
	 other than 'ComDllMain', you'll need to tweak the invocation below.
      */
#if __GLASGOW_HASKELL__ >= 408
      startupHaskell( sizeof(args) / sizeof(char*)
		    , args
		    , &__stginit_ComDllMain
		    );
#else
      startupHaskell(sizeof(args) / sizeof(char*), args);
#endif
      comDll = newComDll(hModule);
      return TRUE;
  } else {
    if (comDll && reason == DLL_PROCESS_DETACH) {
        (comDll)->dllUnload();
	shutdownHaskell();
	/* Not properly letting go of memory here is rude, but we're shutting down.. */
	comDll=NULL;
    }
    return TRUE;
  }
}

HRESULT
STDCALL
DllCanUnloadNow (void)
{
  if (comDll) {
     return (comDll)->dllCanUnloadNow();
  } else {
     return S_OK;
  }
}

HRESULT
STDCALL
DllRegisterServer (void)
{
  if (comDll) {
     return (comDll)->dllRegisterServer();
  } else {
    return E_FAIL;
  }
}

HRESULT
STDCALL
DllUnregisterServer (void)
{
  if (comDll) {
    return (comDll)->dllUnregisterServer();
  } else {
    return E_FAIL;
  }
}

HRESULT
STDCALL
DllGetClassObject
  ( CLSID* rclsid
  , IID*   riid
  , void** ppv
  )
{
  HRESULT hr;
  if (comDll) {
     hr = (comDll)->dllGetClassObject(rclsid, riid, ppv);
     return S_OK;
  } else { 
     return E_FAIL;
  }
}