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

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

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

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

VBA

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

C++

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

Q&A

1回答

983閲覧

VBA、DLL(C++)での、多次元配列の値渡し、戻り値について

chenkenvvt

総合スコア0

DLL

DLL(Dynamic Link Library)とは、他のモジュールからも使用する事が出来る、関数とデータが格納されているモジュールのことです。

VBA

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

C++

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

0グッド

0クリップ

投稿2023/05/23 16:13

実現したいこと

値の入力出力をVBA側の担当
計算をDLL(C++)側の担当
とするようなプログラムを作成する上で以下の内容を知りたいです。

①VBAよりDLL(C++)への多次元配列の値渡し(3次元配列まで)
②DLL(C++)からの複数の戻り値の取得

使用ソフト

Excel 2019
Visual Studio 2017

現在までに出来ていること

1次元配列の値渡し

ソースコード(VBA側)

Declare Function T1 Lib "●●.dll" (ByVal a As Long, ByRef b As Long) As Long

Dim a As Long
Dim b(2) As Long

Public Sub TEST1()

a = 1
b(0) = 400
b(1) = 5000
b(2) = 60

'出力されるのは461
Debug.Print P1(a, b(0))

End Sub

ソースコード(DLL(C++)側)

.cpp

int __stdcall T1(int a, int b[])
{
int x;
x = 0;
x = a + b[0] + b[2];
return x;
}

.def

EXPORTS
T1

こんな感じなことが出来れば・・・・

DLL(C++)側

//宣言のやり方が正しいかは不明
int x[3];
x = 0;

x[0] = b[0][0][0] + b[0][0][1];
x[1] = a + b[0][1][0] + b[0][1][1];
x[2] = b[1][0][0] + b[1][0][1];
x[3] = a + b[1][1][0] + b[1][1][1];

//複数の計算結果を持って帰る(ここは多次元配列は求めていないため、1次配列かその他の方法)
return x[3];

VBA側
Dim b(1,1,1) As Long

a = 1000
b(0,0,0) = 0
b(0,0,1) = 1
b(0,1,0) = 2
b(0,1,1) = 3
b(1,0,0) = 4
b(1,0,1) = 5
b(1,1,0) = 6
b(1,1,1) = 7

上記の値を持たせてDLLを呼び出すと
4種類の計算結果が返ってくる

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

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

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

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

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

Bull

2023/05/25 02:27

一次元配列であれば DLL (C++) 側にそのまま渡せますが、二次元配列以上ですと VBA と C++ でメモリの配置が違うので、そのまま渡しても正常にアクセスできないです。 C++ は二次元配列は列方向がメモリに順番に格納されますが、VBA では行方向が順番に格納されます。 VBA から DLL (C++) に二次元配列を渡すときは、C++ では一次元配列 (ポインタ) として受け取り、インデックスを計算してアクセスする必要があります。 DLL から VBA に配列を返すのはややこしいので、予め VBA 側で配列を用意して、DLL に渡し DLL 側で値をセットするのが確実のように思います。 どうしても戻り値にしたい場合、多分ですが VARIANT 型を使用すればできるのでないかと思います。 おそらく SAFEARRAY を使用することになると思いますが、経験がないので具体的なコードは提示できないです。
guest

回答1

0

時間がとれたんでサンプルを作ってみました。
10行3列の数値データが入力されたワークシートで次のVBAを動かします。

VBA

1Public Declare Sub Average Lib "TEST.dll" (ByRef a As Long, ByVal row As Long, ByVal col As Long, ByRef b As Double) 2 3Option Base 0 4Private Sub CommandButton1_Click() 5 Dim a(9, 2) As Long 6 Dim b(2) As Double 7 For i = 0 To 9 8 For j = 0 To 2 9 a(i, j) = Cells(i + 4, j + 4) 10 Next j 11 Next i 12 13 Call Average(a(0, 0), 10, 3, b(0)) 14 15 For j = 0 To 2 16 Cells(14, j + 4).Value = b(j) 17 Next j 18End Sub

DLL (C++)はこのようなプログラムです。

C++

1extern "C" __declspec(dllexport) void __stdcall Average(long array[], long rows, long cols, double avg[]) 2{ 3 for (int i = 0; i < cols; ++i) { 4 int sum = 0; 5 for (int j = 0; j < rows; ++j) { 6 sum += array[j + i * rows]; 7 } 8 avg[i] = (double)sum / rows; 9 } 10}

そうすると、列ごとに算出された平均値がエクセルのセルに入力されます。
ワークシート

投稿2023/05/26 08:00

Bull

総合スコア986

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問