Haskell from Excel
HaskellのモジュールをExcelから呼び出す方法がかかれたBlogをみつけたので、実際に自分の環境でやってみました。
Calling Haskell from Excel
http://flxldn.tumblr.com/post/163596541/calling-haskell-from-excel
しかし環境が違うためか、残念ながらできませんでした。せっかくなので覚えとして書きたいと思います。
(いろいろやってみてXLLアドインの勉強にはありましたが・・)
C++からHaskellの呼び出し、ExcelからのC++(XLL)呼び出しはできますが、つなげると以下のようなアラートがでました。
XLLは、xlw(A Wrapper for the Excel API)を使う方法と、Excel 2010 XLL SDKを使う方法と、二通りやりました。
参考)
xlw :http://xlw.sourceforge.net/
http://d.hatena.ne.jp/teramonagi/20110124/1295866787
xll sdk:
http://www.microsoft.com/en-us/download/details.aspx?id=20199
テスト環境 Excel 2010 + xlw ver5, Visual Studio 2010 / Windows 7
まずHaskellソースからDLLを作成します。
addr.hs
module Adder where adder :: Int -> Int -> IO Int --gratuitous use of IO adder x y = return (x+y) foreign export stdcall adder :: Int -> Int -> IO Int
adder.h
#ifdef __cplusplus extern “C” { #endif __declspec(dllexport) void __stdcall HsBegin(void); __declspec(dllexport) void __stdcall HsEnd(void); __declspec(dllexport) long __stdcall adder(long x, long y); #ifdef __cplusplus } #endif
adder.def
LIBRARY Adder EXPORTS adder@8=_adder HsBegin@0=_HsBegin HsEnd@0=_HsEnd
dllMain.c
static char* args[] = {"ghcDll" , NULL }; BOOL STDCALL DllMain( HANDLE hModule, DWORD reason, void* reserved) { return TRUE;} __stdcall void HsBegin() { startupHaskell(1, args, __stginit_Adder); } __stdcall void HsEnd() { hs_exit(); }
以下コンパイル手順です。(VisualStudio2010コマンドプロンプト)
ghc -static -c adder.hs -fglasgow-exts
ghc -static -c dllMain.c
ghc -static -shared -o adder.dll adder.o adder_stub.o dllMain.o
lib /MACHINE:x86 /DEF:adder.def /OUT:adder.lib /NOLOGO /SUBSYSTEM:WINDOWS
出力されたadder.dllはSystem32フォルダにコピーします。
次に、XLLファイルを作成します。
xlwのインストールディレクトリの中にあるxlwTemplateExtractor.exe実行すると、XLL_Projectというフォルダがマイドキュメントに作成されるので、ここにあるソリューションを開きます。
デフォルトのEchoShortの下に追加して以下のようになります。
#include<cppinterface.h> #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void __stdcall HsBegin(void); __declspec(dllexport) void __stdcall HsEnd(void); __declspec(dllexport) long __stdcall adder(long x, long y); #ifdef __cplusplus } #endif #pragma warning (disable : 4996) short // echoes a short EchoShort(short x // number to be echoed ) { return x; } short funcAdd(short d1, short d2){ return adder(d1, d2); //return d1 + d2; }
cppinterface.hにはfuncAddのプロトタイプを追加します。
xlwWrapper.cppというソースは自動で生成されるようです。
adder.libを参照するようにします。
まずコメントしてあるd1+d2で成功したことを確認してから、adderのテストしました。
すると上記アラートがでます。
ここで、HsBegin、HsEndを使い方を元のブログを見てみると、ライブラリ自体のmakeが必要のようだったのであきらめ、次にXLL SDKをテストしました。(ライブラリを変更してもたぶん結果は同じという気もしましたし)
XLL SDKをインストールしたフォルダ内にある、EXAMPLEプロジェクトを使用します。
他の関数を参考にして、
#define rgFuncsRows 30 static LPWSTR rgFuncs[rgFuncsRows][7] = { .... {L"CalcCircum", L"BB", L"CalcCircum"}, {L"funcAdd", L"III", L"funcAdd"} }; .... __declspec(dllexport) double WINAPI CalcCircum(double pdRadius) { return pdRadius * 6.283185308; } __declspec(dllexport) short WINAPI funcAdd(short x, short y) { return (short)adder((long)x,(long)y); //return x + y; }
このソースのxAutoOpen()、xAutoClose()にそれぞれHsBegin()、HsEnd()を追加。これらとadderの宣言部もxlwと同様に追加。
これもreturn x+yで動作確認後、Haskell呼び出し部をテストしました。それで上記アラートが出ました。
Excel-DNAてadder.dllを、とも思いましたが、あれはマネージDLLでした。
成果が何もないのもなんなので、cppコンソールアプリでHaskell呼び出しをしてみました。(adder.dllはexeと同じところに置く)
#include "stdafx.h" #ifdef __cplusplus extern "C" { #endif __declspec(dllexport) void __stdcall HsBegin(void); __declspec(dllexport) void __stdcall HsEnd(void); __declspec(dllexport) long __stdcall adder(long x, long y); #ifdef __cplusplus } #endif int _tmain(int argc, _TCHAR* argv[]) { HsBegin(); printf("adder : %d\n", adder(1,2)); HsEnd(); getchar(); return 0; }
3 を表示します。
また解決したらつづきを書きたいと思います。