Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Excelから自作DLLを呼び出す(64ビット版)

はじめに

自作したライブラリ関数を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作成方法を参考にソースコードを書きました。

incometax.d
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のコード例

Module1
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円)を超える方は、この関数使えないですね。:wink:

実行結果

a.png

B3セルに計算式=IF(B2<0,0,INCOMETAX(B2))をセットすることで、B2セルに入力した課税所得金額から所得税を算出できるようになりました。

おまけ1

64ビット版のDLLモジュールをC++でも作成してみました。

incometax.cpp
// 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は不要。
Module1_calc
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にアクセスする

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away