質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Haskell

Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

157閲覧

Haskellで作成したDLLをExcel VBAから安定して利用できない(依存DLL不足ではない)

takedahaskell

総合スコア1

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Haskell

Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2025/06/08 06:58

編集2025/06/08 07:06

実現したいこと

Haskellで作成したDLL(MyLib.dll)をExcel VBAから呼び出し、ワークシート関数として安定して利用したい。

環境】
Windows 10/11(バージョン明記)

Visual Studio 2022

GHC(Haskellコンパイラ)バージョン

Excel(32/64ビット、バージョン明記)

VBA

発生している問題・分からないこと

DLLのビルドは正常に完了し、VBAからDeclare文で呼び出しを試みている

依存DLL不足を疑い、Dependency Walkerで調査したが、「API-MS-」「EXT-MS-」系のみがnot foundで、libHS*やVCランタイム等の不足はなかった

DLLロード時の初期化(DllMain等)は推奨されないため、VBAから明示的に初期化関数を呼び出す方式も試したが、初期化直後にワークシートで関数を使うとExcelが再計算・ブック再オープンを経て正常動作するなど、安定しない。だから、DLLロード時の初期化を進めることにした。
しかし、
「ファイルが見つからない」エラー(エラー48等)が頻発し、依存DLL不足でないことが明らかになった今、解決策が見つからず手詰まり

【確認・試行済み事項】
依存DLL不足なし(Dependency Walkerで確認)

パス、権限、32/64ビット不一致、Excelのキャッシュ等も再確認

DLLの再ビルド・再配置も実施

VBAからの初期化呼び出し方式も試行

エラーメッセージ

error

1vbaでTestDllLoadWithErrorCheckを実行すると、エラーコード0が出る。 2TestTestFuncを実行すると、ファイルが見つかりません。(エラー 48)というエラーが出る。

該当のソースコード

MyLib.hs

1{-# LANGUAGE ForeignFunctionInterface #-} 2module MyLib where 3 4import Foreign 5import Foreign.C.Types 6import Foreign.C.String (CWString, peekCWString) 7import qualified Data.Map.Strict as Map 8import Data.Char (isSpace, ord) 9import System.IO (hPutStrLn, stderr) 10 11-- Mapの値をEither String Int型にする 12myDict :: Map.Map Int (Either String Int) 13myDict = Map.fromList [ 14 (32, Right 0), 15 (33, Right 1), 16 (38, Right 25), 17以下続く 18(12291, Right 1), 19 (65293, Right 1) 20 ] 21 22-- C言語から呼び出せるようにエクスポート 23{-# LANGUAGE ForeignFunctionInterface #-} 24 25-- 文字列のn番目(1始まり)のUnicode値を返す(空白は除去) 26foreign export ccall real_len :: CWString -> CInt -> CInt -> IO CInt 27 28real_len :: CWString -> CInt -> CInt -> IO CInt 29real_len cws elem1 elem2 = do 30 hPutStrLn stderr "real_len: 関数が呼ばれました" 31 str <- peekCWString cws -- ここでUTF-16(BSTR)を正しくHaskellのStringに変換 32 hPutStrLn stderr $ "real_len: 入力文字列=" ++ str 33 let strNoSpaces = filter (not . isSpace) str 34 idx = fromIntegral elem2 - 1 -- elem2は1始まり 35 if null strNoSpaces || idx < 0 || idx >= length strNoSpaces 36 then do 37 hPutStrLn stderr "real_len: 範囲外または空文字列" 38 return (-1) 39 else do 40 let ch = strNoSpaces !! idx 41 hPutStrLn stderr $ "real_len: 抽出文字=" ++ [ch] 42 return (fromIntegral . ord $ ch)

wrapper.c

1#include <windows.h> 2#include <oleauto.h> // BSTR用 3#include <HsFFI.h> 4#include <wchar.h> 5#include <stdio.h> // printf用 6 7#ifdef __cplusplus 8extern "C" { 9#endif 10 11 // Haskell関数の宣言 12 extern HsInt32 real_len(const wchar_t* s, HsInt32 elem1, HsInt32 elem2); 13 14 // DLLロード時にHaskellランタイムを初期化 15 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { 16 static int initialized = 0; 17 if (fdwReason == DLL_PROCESS_ATTACH && initialized == 0) { 18 int argc = 0; 19 char** argv = NULL; 20 hs_init(&argc, &argv); 21 initialized = 1; 22 } 23 return TRUE; 24 } 25 26 // VBAから呼び出すラッパー 27 __declspec(dllexport) HsInt32 __stdcall real_len_wrapper(BSTR s, HsInt32 elem1, HsInt32 elem2) { 28 MessageBoxW(NULL, L"real_len_wrapper called", L"Debug", MB_OK); // ←ここで呼ぶ 29 OutputDebugStringA("real_len_wrapper: 関数が呼ばれました\n"); 30 if (s == NULL) { 31 OutputDebugStringA("real_len_wrapper: BSTRがNULLです\n"); 32 return -1; 33 } 34 // BSTRはwchar_t*として使える。Haskell側もCWStringでOK 35 return real_len((const wchar_t*)s, elem1, elem2); 36 } 37 38 // ★テスト用の引数なし関数 39 __declspec(dllexport) int __stdcall test_func() { 40 MessageBoxW(NULL, L"test_func called", L"Debug", MB_OK); 41 OutputDebugStringA("test_func: called\n"); 42 return 42; 43 } 44 45#ifdef __cplusplus 46} 47#endif 48

StartEnd.c

1#include <HsFFI.h> 2#include <stddef.h> // ← これを追加 3 4// DllMainは絶対に定義しないでください 5 6// Haskellランタイムの手動初期化関数 7void HsStart() { 8 int argc = 1; 9 char* argv[] = { "ghcDll", NULL }; 10 char** args = argv; 11 hs_init(&argc, &args); 12} 13 14// Haskellランタイムの手動終了関数 15void HsEnd() { 16 hs_exit(); 17} 18

vba

1' 64ビットExcel専用のDLL/API宣言 2Declare PtrSafe Function real_Len_wrapper Lib "D:\visual_studio_2022\Git_repos_folderpath\MyLib.dll" Alias "real_len_wrapper" (ByVal s As String, ByVal elem1 As Long, ByVal elem2 As Long) As Long 3Declare PtrSafe Function test_func Lib "D:\visual_studio_2022\Git_repos_folderpath\MyLib.dll" () As Long 4Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr 5Declare PtrSafe Function FreeLibrary Lib "kernel32" (ByVal hLibModule As LongPtr) As Long 6Declare PtrSafe Function GetLastError Lib "kernel32" () As Long 7 8' DLLロードとエラー取得のテスト 9Sub TestDllLoadWithErrorCheck() 10 Dim hLib As LongPtr 11 Dim errCode As Long 12 Dim dllPath As String 13 dllPath = "D:\visual_studio_2022\Git_repos_folderpath\MyLib.dll" 14 15 If Dir(dllPath) = "" Then 16 MsgBox "DLLが見つかりません: " & dllPath, vbCritical 17 Exit Sub 18 End If 19 20 hLib = LoadLibrary(dllPath) 21 If hLib = 0 Then 22 errCode = GetLastError() 23 MsgBox "DLLのロード失敗 - エラーコード: " & errCode, vbCritical 24 Else 25 Debug.Print "DLLロード成功: " & hLib 26 FreeLibrary hLib 27 End If 28End Sub 29 30' セルの値をDLL関数に渡して長さを取得する関数 31Function Real_Len1(rng As Range, elem1 As Long, elem2 As Long) As Long 32 Dim s As String 33 Dim errCode As Long 34 35 On Error Resume Next 36 s = rng.Value 37 38 If Len(s) = 0 Then 39 Real_Len1 = -1 40 Exit Function 41 End If 42 43 ' DLL関数を直接呼び出す 44 Real_Len1 = real_Len_wrapper(s, elem1, elem2) 45 errCode = GetLastError() 46 If errCode <> 0 Then 47 Debug.Print "real_len_wrapper呼び出しエラー: " & errCode 48 End If 49End Function 50 51' DLLのtest_funcを呼び出して動作確認 52Sub TestTestFunc() 53 Dim ret As Long 54 ret = test_func() 55 MsgBox "test_funcの戻り値: " & ret 56End Sub 57 58

LIBRARY MyLib
EXPORTS
real_len_wrapper

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

AIに聞いてコードを書いた。

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

自己解決

自己解決できました。読んでくれた方には申し訳ないです。

投稿2025/06/10 08:07

takedahaskell

総合スコア1

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SaitoAtsushi

2025/06/11 02:04

自己解決した場合はどのように解決したのかも書くのが望ましいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問