はじめに
自作したライブラリ関数をExcelでも使いたい場合を考えてみました。
ExcelからDLLを呼び出すことができるので、自作したライブラリ関数をDLLにするとよさそうです。
以下は、実際に作ってみたものの紹介です。
環境
- Windows 10
- Microsoft Excel for Office 365 MSO (16.0.12527.21230) 64bit
- DMD v2.094.0
DLLのソースコード
使用するExcel
が64ビット版のため、DLLモジュールも対応する64ビット版を作成します。
32ビット版のDLL作成方法を参考にソースコードを書きました。
import core.sys.windows.windows;
import core.sys.windows.dll;
import std.algorithm.searching;
__gshared HINSTANCE g_hInst;
extern (Windows)
BOOL DllMain(HINSTANCE hInstance, ULONG ulReason, LPVOID pvReserved)
{
switch (ulReason){
case DLL_PROCESS_ATTACH:
g_hInst = hInstance;
dll_process_attach(hInstance, true);
break;
case DLL_PROCESS_DETACH:
dll_process_detach(hInstance, true);
break;
case DLL_THREAD_ATTACH:
dll_thread_attach(true, true);
break;
case DLL_THREAD_DETACH:
dll_thread_detach(true, true);
break;
default:
}
return ( true );
}
export extern (Windows)
int calcIncomeTax(int income)
{
income = income / 1000 * 1000; // 千円未満の端数金額を切り捨て
int[] boundary = [1_950_000, 3_300_000, 6_950_000, 9_000_000, 18_000_000, 40_000_000];
int[] taxrate = [5, 10, 20, 23, 33, 40, 45];
int[] deduction = [0, 97_500, 427_500, 636_000, 1_536_000, 2_796_000, 4_796_000];
auto index = count!("a < b")(boundary, income);
return ( income / 100 * taxrate[index] - deduction[index] );
}
ソースコードの説明
DLL の初期化にある通り、 DLL の初期化や終了に必要なDllMain
を記述します。
calcIncomeTax
関数は、課税所得から所得税を計算する関数です。
Excelから呼び出すことができるよう、export extern (Windows)
とします。
count関数を使うことでif
分岐を多用せずにスッキリさせてみました。ちなみにcount
関数を使わなければ、以下のような実装例になると思います。
int calcIncomeTax(int income)
{
income = income / 1000 * 1000; // 千円未満の端数金額を切り捨て
int itax; // 所得税
if ( income < 1_950_000 ){
itax = income / 100 * 5;
} else if ( income < 3_300_000 ){
itax = income / 100 * 10 - 97_500;
} else if ( income < 6_950_000 ){
itax = income / 100 * 20 - 427_500;
} else if ( income < 9_000_000 ){
itax = income / 100 * 23 - 636_000;
} else if ( income < 18_000_000 ){
itax = income / 100 * 33 - 1_536_000;
} else if ( income < 40_000_000 ){
itax = income / 100 * 40 - 2_796_000;
} else {
itax = income / 100 * 45 - 4_796_000;
}
return ( itax );
}
所得税の計算方法については、こちらを参照してください。
DLL作成のコマンド実行例
D:\Dev> dmd -m64 -shared -L/SUBSYSTEM:WINDOWS -ofincometax.dll incometax.d
ライブラリ incometax.lib とオブジェクト incometax.exp を作成中
コンパイルの結果、incometax.dll
が作成されます。
Excelから呼び出せるように、環境変数PATH
に記述があるフォルダにincometax.dll
を配置します。(例えば、C:\WINDOWS\system32
)
Excel側VBAのコード例
Declare PtrSafe Function calcIncomeTax Lib "incometax.dll" (ByVal income As Long) As Long
Function incometax(income as Long) As Long
incometax = calcIncomeTax(income)
End Function
Declareステートメントを参考にDLLでexport
したcalcIncomeTax
関数をDeclare
します。
64ビット版のExcel
で実行する場合は、Declare
ステートメントにPtrSafe
キーワードが必要です。
calcIncomeTax
は、D言語で引数、戻り値ともにint
型で定義しています。
D言語でのint
型は32ビットなので、VBAでは32ビットに該当するLong
型としています。
※つまり、課税所得が20億円(正確には 2,147,483,647円)を超える方は、この関数使えないですね。
実行結果
B3セルに計算式=IF(B2<0,0,INCOMETAX(B2))
をセットすることで、B2セルに入力した課税所得金額から所得税を算出できるようになりました。
おまけ1
64ビット版のDLLモジュールをC++でも作成してみました。
// cl /clr /LD incometax.cpp
#define VC_DLL_EXPORTS extern "C" __declspec(dllexport)
VC_DLL_EXPORTS int __stdcall calcIncomeTax1(int income)
{
income = income / 1000 * 1000; // 千円未満の端数金額を切り捨て
int itax; // 所得税
if ( income < 1950000 ){
itax = income / 100 * 5;
} else if ( income < 3300000 ){
itax = income / 100 * 10 - 97500;
} else if ( income < 6950000 ){
itax = income / 100 * 20 - 427500;
} else if ( income < 9000000 ){
itax = income / 100 * 23 - 636000;
} else if ( income < 18000000 ){
itax = income / 100 * 33 - 1536000;
} else if ( income < 40000000 ){
itax = income / 100 * 40 - 2796000;
} else {
itax = income / 100 * 45 - 496000;
}
return ( itax );
}
おまけ2
Microsoft Excel
の代わりにLibreOffice Calc
(64ビット)版のVBAからもDLLを呼び出せました。
Excel
版VBAとのソースコードの違いは、以下の2点です。
- 先頭に
Option VBASupport 1
を追加。 -
Declare
宣言にPtrSafe
は不要。
Option VBASupport 1
Declare Function calcIncomeTax Lib "incometax.dll" (ByVal income As Long) As Long
Function incometax(income As Long) As Long
incometax = calcIncomeTax(income)
End Function
参考情報
D言語での32ビット版のDLL作成方法
所得税の税率、計算方法
count関数(phobos)
ExcelでDLLにアクセスする