6 changed files with 205 additions and 3 deletions
@ -1,6 +1,25 @@
@@ -1,6 +1,25 @@
|
||||
module Main where |
||||
|
||||
import Lib |
||||
import QuoteSource.DDE |
||||
import QuoteSource.DataImport |
||||
import Control.Concurrent |
||||
import Control.Monad |
||||
|
||||
import Graphics.UI.FLTK.LowLevel.FL |
||||
import Graphics.UI.FLTK.LowLevel.FLTKHS |
||||
|
||||
callback :: DdeCallback |
||||
callback = undefined |
||||
|
||||
main :: IO () |
||||
main = someFunc |
||||
main = do |
||||
dis <- initDataImportServer "atrade" |
||||
forever $ threadDelay 1000 |
||||
window <- windowNew (Size (Width 320) (Height 170)) |
||||
Nothing Nothing |
||||
end window |
||||
showWidget window |
||||
_ <- run |
||||
return () |
||||
|
||||
|
||||
@ -0,0 +1,114 @@
@@ -0,0 +1,114 @@
|
||||
{-# LANGUAGE ForeignFunctionInterface #-} |
||||
|
||||
module QuoteSource.DDE ( |
||||
initializeDde, |
||||
DdeState, |
||||
DdeCallback, |
||||
ddeResultAck, |
||||
ddeResultTrue, |
||||
ddeResultFalse, |
||||
ddeXtypConnect, |
||||
ddeXtypPoke, |
||||
ddeCpWinAnsi, |
||||
queryString, |
||||
nullDdeState |
||||
) where |
||||
|
||||
import Control.Applicative |
||||
import Control.Exception |
||||
import Control.Monad |
||||
import Data.Bits |
||||
import Data.Typeable |
||||
import System.Win32.DLL |
||||
import System.Win32.Types |
||||
import Foreign |
||||
import Foreign.C.Types |
||||
import Foreign.C.String |
||||
|
||||
data DdeException = ApiError String |
||||
deriving (Show, Typeable) |
||||
|
||||
ddeResultAck :: HANDLE |
||||
ddeResultAck = wordPtrToPtr $ bit 15 |
||||
|
||||
ddeResultTrue :: HANDLE |
||||
ddeResultTrue = wordPtrToPtr $ bit 1 |
||||
|
||||
ddeResultFalse :: HANDLE |
||||
ddeResultFalse = wordPtrToPtr $ bit 0 |
||||
|
||||
ddeXtypConnect :: CUInt |
||||
ddeXtypConnect = 0x1062 |
||||
|
||||
ddeXtypPoke :: CUInt |
||||
ddeXtypPoke = 0x4090 |
||||
|
||||
ddeCpWinAnsi = 1004 |
||||
|
||||
instance Exception DdeException |
||||
|
||||
foreign import stdcall unsafe "windows.h DdeInitializeW" |
||||
ddeInitialize :: LPDWORD -> FunPtr DdeCallback -> DWORD -> DWORD -> IO CUInt |
||||
|
||||
foreign import stdcall unsafe "windows.h DdeUninitialize" |
||||
ddeUninitialize :: DWORD -> IO BOOL |
||||
|
||||
foreign import stdcall unsafe "windows.h DdeCreateStringHandleW" |
||||
ddeCreateStringHandle :: DWORD -> LPSTR -> CInt -> IO HANDLE |
||||
|
||||
foreign import stdcall unsafe "windows.h DdeFreeStringHandleW" |
||||
ddeFreeStringHandle :: DWORD -> LPSTR -> IO HANDLE |
||||
|
||||
foreign import stdcall unsafe "windows.h DdeNameService" |
||||
ddeNameService :: DWORD -> HANDLE -> HANDLE -> CInt -> IO HANDLE |
||||
|
||||
foreign import stdcall unsafe "windows.h DdeCmpStringHandles" |
||||
ddeCmpStringHandles :: HANDLE -> HANDLE -> IO CInt |
||||
|
||||
foreign import stdcall unsafe "windows.h DdeQueryStringW" |
||||
ddeQueryString :: DWORD -> HANDLE -> CString -> DWORD -> CInt -> IO DWORD |
||||
|
||||
foreign import stdcall "wrapper" |
||||
mkCallbackPtr :: DdeCallback -> IO (FunPtr DdeCallback) |
||||
|
||||
data DdeState = DdeState { |
||||
ddeInstance :: DWORD, |
||||
appName :: HANDLE, |
||||
topicName :: HANDLE, |
||||
callback :: FunPtr DdeCallback |
||||
} |
||||
|
||||
nullDdeState = DdeState { ddeInstance = 0, appName = nullPtr, topicName = nullPtr, callback = nullFunPtr } |
||||
|
||||
type DdeCallback = CUInt -> CUInt -> HANDLE -> HANDLE -> HANDLE -> HANDLE -> LPDWORD -> LPDWORD -> IO HANDLE |
||||
|
||||
initializeDde :: String -> String -> DdeCallback -> IO DdeState |
||||
initializeDde appName topicName callback = alloca (\instancePtr -> do |
||||
cb <- mkCallbackPtr callback |
||||
rc <- ddeInitialize instancePtr cb 0 0 |
||||
instanceRaw <- peek instancePtr |
||||
when (rc /= CUInt 0) $ throw $ ApiError "Unable to initialize DDE" |
||||
|
||||
withCString appName (\appNameRaw -> withCString topicName (\topicNameRaw -> do |
||||
appNameHandle <- ddeCreateStringHandle instanceRaw appNameRaw 0 |
||||
topicNameHandle <- ddeCreateStringHandle instanceRaw topicNameRaw 0 |
||||
when (appNameHandle == nullHANDLE || topicNameHandle == nullHANDLE) $ throw $ ApiError "Unable to create strings handles" |
||||
|
||||
rc2 <- ddeNameService instanceRaw appNameHandle nullPtr 1 |
||||
when (rc2 == nullHANDLE) $ throw $ ApiError $ "Unable to register application name: " ++ appName |
||||
|
||||
return DdeState { ddeInstance = instanceRaw, appName = appNameHandle, topicName = topicNameHandle, callback = cb } ))) |
||||
|
||||
destroyDde :: DdeState -> IO () |
||||
destroyDde state = do |
||||
freeHaskellFunPtr $ callback state |
||||
ddeUninitialize $ ddeInstance state |
||||
return () |
||||
|
||||
queryString :: DdeState -> Int -> HANDLE -> IO (Maybe String) |
||||
queryString state maxSize handle = allocaBytes maxSize (\x -> do |
||||
rc <- ddeQueryString (ddeInstance state) handle x (toEnum maxSize) ddeCpWinAnsi |
||||
if rc == 0 |
||||
then return Nothing |
||||
else Just <$> peekCAString x) |
||||
|
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
|
||||
module QuoteSource.DataImport |
||||
( |
||||
initDataImportServer, |
||||
ServerState |
||||
) where |
||||
|
||||
import Foreign.Marshal.Alloc |
||||
import System.Win32.DLL |
||||
import System.Win32.Types |
||||
import Foreign |
||||
import Foreign.C.Types |
||||
import Foreign.C.String |
||||
|
||||
import QuoteSource.DDE |
||||
import Data.IORef |
||||
|
||||
data ServerState = ServerState { |
||||
dde :: DdeState, |
||||
appName :: String |
||||
} |
||||
|
||||
ddeCallback :: IORef ServerState -> CUInt -> CUInt -> HANDLE -> HANDLE -> HANDLE -> HANDLE -> LPDWORD -> LPDWORD -> IO HANDLE |
||||
ddeCallback state msgType format hConv hsz1 hsz2 hData dwData1 dwData2 = do |
||||
putStrLn "Callback" |
||||
return nullHANDLE |
||||
|
||||
{- |
||||
| msgType == ddeXtypConnect = handleConnect state hsz1 hsz2 |
||||
| msgType == ddeXtypPoke = handlePoke state hsz1 hData |
||||
| otherwise = do |
||||
print msgType |
||||
return nullHANDLE |
||||
where |
||||
handleConnect state hsz1 hsz2 = do |
||||
myAppName <- appName <$> readIORef state |
||||
myDdeState <- dde <$> readIORef state |
||||
maybeAppName <- queryString myDdeState 256 hsz2 |
||||
putStrLn "Connect" |
||||
case maybeAppName of |
||||
Just incomingAppName -> do |
||||
putStrLn incomingAppName |
||||
return $ if incomingAppName == myAppName |
||||
then ddeResultTrue |
||||
else ddeResultFalse |
||||
Nothing -> return ddeResultFalse |
||||
|
||||
handlePoke state hsz1 hData = do |
||||
putStrLn "Poke" |
||||
return ddeResultAck |
||||
-} |
||||
|
||||
|
||||
initDataImportServer :: String -> IO (IORef ServerState) |
||||
initDataImportServer applicationName = do |
||||
s <- newIORef ServerState { appName = applicationName, dde = nullDdeState } |
||||
d <- initializeDde applicationName "default" (ddeCallback s) |
||||
modifyIORef s (\state -> state {dde = d}) |
||||
putStrLn "DataImportServer initialized" |
||||
return s |
||||
Loading…
Reference in new issue