2012-03-19 10 views
7

.NET GUIを使用したHaskellアプリケーションを作成したいと考えています。これは、手動でする必要がなくなり.NET GUIを使用したHaskellアプリケーションの作成

  1. :私はと私はHaskellの一部は、.NETコードを呼び出す実行可能であるべきだと思う、それのパッケージ管理などを活用するために、私のビルドツールとして徒党を使用したいのですがここで説明するようにHaskellのRTCを初期化:http://www.haskell.org/ghc/docs/7.0.3/html/users_guide/win32-dlls.html

  2. 徒党を簡単にWindowsのDLLを生成することはできません。http://www.haskell.org/haskellwiki/Cabal/Developer-FAQ#Building_DLLs__with_Cabal

私はを使用しての.NETを呼び出すHaskellの実行ファイルを作成することがかなり容易見つけましたですが、ハスケルにコールバックするためのGUIコードも必要です。私はHaskellの "foreign export"コマンドを使用してこれを実現し、.NETネイティブinterop経由でこのエクスポートされた関数を呼び出すことを望んでいました。しかし、「外部エクスポート」機能は実行可能ファイルにエントリポイントを作成していないようですが、実行時にdumpbin /EXPORTSを実行するとエントリポイントが表示されません。 -sharedスイッチを使用してDLLを作成するときにGHCのみのエントリポイントを作成するか、カバルにエントリポイントの作成を抑制するフラグを追加するかどうかはわかりません。

私はWindowsの実行可能ファイルにエントリポイントを作成するためにGHCに強制する必要があると思いますか?または、Haskell DLLを作成し、Haskell RTCを手動で初期化するために必要なステップを実行するのに、.NET実行可能ファイルを使用する方が良いでしょうか?

+0

あなたは本当に.netとhaskellでコード化したいですか?それから私はdllであなたのhaskellを取得し、.netから関数を呼び出すことを提案します。あなたのポイント1は克服するのは簡単ですし、カバールがいい場合でも、あなたのポイント2はヒントのほうが多く(つまり使用しないように).netパートを構築するために別のものを使用する必要があります。 – Jonke

答えて

4

私は通常、コールバックを関数ポインタとして渡すことでこれを解決します。たとえば、ボタンを押すとハスケルにコールバックする必要があるアプリがあります(私はCocoaを使用していますが、名前は非常に似ています)。

まず、NSButtonオブジェクトをサブクラス化し、新しいButtonCクラスにvoid(*onClickCallback)()というプライベートメンバーを与えます。また、関数を宣言します。void setClickCallback(ButtonC *button, void(*callback)());ボタンをクリックするたびに関数ポインタが呼び出されるように、サブクラスを実装します。 .Netでは、デリゲートでこれを行う巧妙な方法があるかもしれません(それは私が.Netを使ってからしばらくありました)。

次に、このように私のHaskellの結合ルックス(いくつかのコードは省略):

module Foreign.Button where 

data ButtonObj 
type ButtonPtr = ForeignPtr ButtonObj 

foreign import ccall unsafe "setClickCallback" 
    c_setClickCallback :: Ptr ButtonObj -> FunPtr (IO()) -> IO() 

foreign import ccall "wrapper" 
    makeClickCallback :: IO() -> IO (FunPtr (IO())) 

buttonSetCallback :: ButtonPtr -> FunPtr (IO()) -> IO() 
buttonSetCallback btn cb = 
    withForeignPtr btn $ \p -> c_setClickCallback p cb 

buttonNew :: IO ButtonPtr 
buttonNew = ... 

今タイプIO()のHaskellのデータがFunPtrで包み、buttonSetCallbackとGUIに渡すことができます。ボタンを押すたびに、IO()アクションが実行されます。 FunPtr Sとの用心する

createButton :: IO ButtonPtr 
createButton = do 
    btn <- buttonNew 
    let buttonClicked = print "The button was clicked!" 
    btnCallback <- makeClickCallback buttonClicked 
    buttonSetCallback btn btnCallback 
    return btn 

ことの一つは、彼らがガベージコレクトされないということです。完了したら手動で割り当てを解除するか、メモリリークが発生します。良い方法は、FunPtrを共有しないことです。また、Haskell側でそれらへの参照を保持しないようにしてください。そうすれば、あなたのオブジェクトはクリーンアップの一部としてFunPtrを解放することができます。これには、すべてのオブジェクト間で共有されるハスケル(freeFunPtr関数)へのもう1つのコールバックが必要で、実行可能ファイルが終了したときに解放されるだけです。

+0

合理的なアプローチのようですFunPtrが作成されると一度推測すれば、それを渡すことができます。NETをIntPtrとして使用しますが、一度.NETの世界にこの関数ポインタがあれば、どのように呼び出すのですか? – Robert

+1

@Robert - デリゲートにマーシャリングしてデリゲートを呼び出すことができます。詳細はhttp://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getdelegateforfunctionpointer.aspx –

+0

サウンド、ありがとう! – Robert

関連する問題