📝

[C#5] コンパイルしないで Excel DNA を使う

2025/01/04に公開

Excel VBAのかわりにC#(あるいはF#, VB.NET)でユーザー定義関数が手軽に作成できるツールである Excel DNA について, DLL を作らずに使う方法を記載(残念ながら F# はデフォルトでは Windows にコンパイラが付属しないので, 今回の記事では対象外). 普通に使う方法については公式のドキュメントを参照のこと.

0. 概要

最近の Excel はいろいろ改良されていて, VBAだけで書いてもあんまり不自由は感じないけれど, たまに C#(あるいはF#, VB.NET) でプログラムを書きたい場面がでてくる. そんな時に一番手軽に使えるツールが Excel DNA だと思う. 通常は Visual Studio 等で DLL を作成しそれを読み込む形で使用するが, 実はC#(とVB.NET)の場合には dna ファイルにプログラムを記載すればコンパイル等せずに直接ユーザー定義関数を作成できる. 昔は公式の Getting Started に記載があったが, 今のドキュメントでは DLL を使う方法がデフォルトになっているようなので, 備忘もかねてメモしておくことにした.

この記事では以下の内容について記載する.

  • インストール方法
  • vscode の設定
  • サンプルプログラム(線形補間の関数)

なお, タイトルに「コンパイルしない」と記載したが, 実際には Excel に読み込む際に裏で Windows 付属の C# コンパイラ(csc.exe) を使ってこっそりコンパイルされているため, 使えるC#のバージョンはC#5になる.

1. インストール方法, 使い方

公式の配布サイト(GitHub)から以下のファイルをダウンロードする(ExcelDna.Integration.dll はより高度なことをやろうとするときに必要だが, とりあえずその時になったらダウンロードすればいいと思う, たぶん).

  • ExcelDna64.dna
  • ExcelDna64.xll

(これは64ビットの Excel 用. Excel が32ビットの場合はファイル名に64がついてないものを使う.)

参考までに GitHub で個別ファイルをダウンロードする方法は以下の通り.

  • ファイル名をクリックしてファイルのページに移動
  • ダウンロードマーク(Download raw file)をクリック

また, 使用方法は以下のとおり.

  • ダウンロードしたファイルを使用したい Excel ファイルと同じフォルダに置く
  • ExcelDna64.dna ファイルを編集し, ユーザー定義関数などを記載
  • Excel ファイルに ExcelDna64.xll ファイルをドラッグ&ドロップ(もしくは「ファイル名を指定して開く」から ExcelDna64.xll ファイルを開く)

これでC#で記載したユーザー定義関数を Excel で使えるようになる.

2. vscode の設定

拡張子が dna のシンタックスハイライトの設定はないので, かわりにC#のシンタックスハイライトを使えるようにする.

vscode の設定項目のうち, files.associations に設定を加える(*.dna ファイルに csharp のシンタックスハイライトを適用).

自分の場合, これでだいたいシンタックスハイライトが使えている. dna ファイルには Excel DNA 独自の記載があるので, 実は何か不具合があるかもしれない. ただ, 個人的にちょこっといじる程度であれば今のところ十分.

3. サンプルプログラム

実際にユーザー定義関数を作ってみよう.

3.1 dna ファイルの編集

ダウンロードした dna ファイルは以下のようになっている.

ExcelDna64.dna
<DnaLibrary RuntimeVersion="v4.0" Language="VB" >
<![CDATA[

    Public Module Module1
        Function AddThem(x, y)
            AddThem = x + y
        End Function    
    End Module

]]>
</DnaLibrary>

RuntimeVersion は .NET Framework のバージョンで, デフォルトでは Windows に付属のコンパイラを使用する前提なので v4.0 が指定されている. これはC#でも同じなので, これはこのままでOK. また初期設定の言語は VB になっているので CS (C#) に変更する(残念ながらここを FS としても F# は使えない). サンプルコードは2つの引数を足すだけのものなので, これも消しておく.

ExcelDna64.dna
<DnaLibrary RuntimeVersion="v4.0" Language="CS" >
<![CDATA[

]]>
</DnaLibrary>

CDATAの中にユーザー定義関数のコードを記載する.

3.2 プログラムのロジック

作成するサンプルプログラムは標本点\{(x_i,y_i)\}からそれを線形につなぐ補間曲線を得るものを考える. 通常使う状況を考慮して, Excel のワークシート上でx座標が格納された列ベクトル(重複なし, 昇順に格納されているものとする), y座標が格納された列ベクトル, 補間で求めたいx座標の3つを引数として受け取り, 補間後の y座標を返す関数を作成する. 補間は簡単のため, 線形補間とする.

念の為, 線形補間のロジックは以下のとおり.

標本点(x_{i-1},y_{i-1})(x_i,y_i) を結ぶ直線は以下のように書ける.

\begin{align*} y&=y_{i-1} + \dfrac{y_i-y_{i-1}}{x_i-x_{i-1}} \cdot (x-x_{i-1}) \\ &=\dfrac{y_{i-1}\cdot(x_i-x)+y_i\cdot(x-x_{i-1}))}{x_i-x_{i-1}} \end{align*}

また補間点の外側(外挿の場合)については端の値を使って定数補間とする.

3.3 サンプルプログラム

このロジックをC#のコードに直す.

ExcelDna64.dna
<DnaLibrary RuntimeVersion="v4.0" Language="CS" >
<![CDATA[

public class Udf
{
  public static double interp(double[,] x, double[,] y, double xx)
  {
    // assumption: x,y are col vector, n>1
    int n=x.GetLength(0);
    double yy=0;
    if(xx<=x[0,0]){
      yy=y[0,0];
    }else if(x[n-1,0]<=xx){
      yy=y[n-1,0];
    }else{
      for(int i=1;i<n;i++){
        if(xx<=x[i,0]){
          yy=(y[i-1,0]*(x[i,0]-xx)+y[i,0]*(xx-x[i-1,0]))
              /(x[i,0]-x[i-1,0]);
          break;
        }
      }
    }
    return yy;
  }
}

]]>
</DnaLibrary>
  • Excel のワークシート上の列ベクトルは Range オブジェクトであるが, 引数の型は double[,] としている. これは VBA で Range オブジェクトを Variant 型で受けたときに2次元配列になるのに似ている.
  • 入力引数に対する仮定として, 列ベクトルであること, 標本点が2点以上あることを仮定している. これは使う側(自分)が保証する.
  • その他エラー処理等はなし.

実際に使ってみた様子は以下のとおり.

ちゃんと補間できてる(\(^o^)/).

4. まとめ

とりあえずテキストエディタ(メモ帳でもOK)さえあれば, C# で Excel のユーザー定義関数を作れる. お手軽ですね.

ところで Excel DNA の開発者の Govert さんは某有名ゲームの配管工のおじさんにしか見えない(笑). Thanks, Govert!

Discussion