packages feed

dx9base-0.1: DirectX9/ComObject.hs

{-#  LANGUAGE ForeignFunctionInterface, MultiParamTypeClasses #-}
module DirectX9.ComObject
where
import Control.Exception    ( bracket_ )
import Foreign.Concurrent   ( addForeignPtrFinalizer )
import Foreign          ( Ptr, poke, peek , castPtr, ForeignPtr, withForeignPtr
                        , nullPtr, mallocForeignPtr )
import System.Win32     ( UINT )


---------------------------------------------------------------------------
-- ComObject

newtype ComObject a = ComObject (ForeignPtr (Ptr a))

comMake :: Ptr a -> IO (ComObject a)
comMake ptr = do
    fp <- mallocForeignPtr
    ptr' <- withForeignPtr fp $ \ptr' ->do
        poke ptr' ptr
        return ptr'
    addForeignPtrFinalizer fp (fin ptr')
    return $ ComObject fp
    where
        fin ptr' = do
            ptr <- peek ptr'
            if ptr==nullPtr
                then return ()
                else c_Release (castPtr ptr) >> return ()

comUnManage :: ComObject a -> IO (Ptr a)
comUnManage obj = withCom obj $ \ptr -> do
    c_AddRef (castPtr ptr)
    return ptr

comFree :: ComObject a -> IO Int
comFree (ComObject o) = withForeignPtr o $ \ptr -> do
    ptr' <- peek ptr
    if ptr'==nullPtr
        then return (-1)
        else do
            c <- c_Release (castPtr ptr')
            poke ptr nullPtr
            return $ fromIntegral c

withCom :: ComObject a -> (Ptr a -> IO b) -> IO b
withCom (ComObject obj) act = withForeignPtr obj $ \ptr -> do
    ptr' <- peek ptr
    if ptr'==nullPtr
        then act ptr'
        else bracket_
            (c_AddRef $ castPtr ptr')
            (c_Release $ castPtr ptr')
            (act ptr')

class ComCast base derived where
    comCast :: ComObject derived -> IO (Maybe (ComObject base))
    withCastedCom :: ComObject derived -> (Ptr base -> IO a) -> IO a
    
    comCast (ComObject obj) = withForeignPtr obj $ \ptr -> do
        ptr' <- peek ptr
        if ptr'==nullPtr
            then return Nothing
            else do
                c_AddRef (castPtr ptr')
                comMake (castPtr ptr') >>= return.Just
    withCastedCom obj act = withCom obj (act.castPtr)
        

foreign import ccall unsafe "fake.h AddRef"
    c_AddRef :: Ptr () -> IO UINT
foreign import ccall unsafe "fake.h Release"
    c_Release :: Ptr () -> IO UINT