みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

VB.NETからC++のdll連携(double)

プログラム初心者です。
double型の配列をVB2010とC++で作成したdllで連携したいのですが、値が正しく渡されません。
値が正しく渡せるにはどうしたら良いでしょうか?

以下がその内容です。(int型の場合)これをdouble型で渡したいのですが。
C++ではSafeArrayの扱いになるとのことですが、方法が良く分かりません。

VBソース
-----------------
' Arrays.vb

Imports System
Imports Microsoft.VisualBasic
Imports System.Runtime.InteropServices

Friend NotInheritable Class NativeMethods

Private Sub New()
End Sub

Declare Function TestArrayOfInts Lib "makedll.dll" ( _
<[In](), Out()> ByVal myArray() As Integer, ByVal size As Integer) As Integer

End Class

Public NotInheritable Class App
Private Sub New()
End Sub
Public Shared Sub Main()

' *************** array ByVal **************
Dim array1(9) As Integer

Console.WriteLine("Integer array passed ByVal before call:")
Dim i As Integer

For i = 0 To array1.Length - 1
array1(i) = i
Console.Write(" " & array1(i))
Next i

Dim sum1 As Integer = NativeMethods.TestArrayOfInts(array1, array1.Length)
Console.WriteLine(ControlChars.CrLf & "Sum of elements:" & sum1)

Console.WriteLine(ControlChars.CrLf & "Integer array passed ByVal after call:")

For Each i In array1
Console.Write(" " & i)
Next i
Console.Read()

End Sub
End Class
//**********************************
C++作成dllソース(makedll.cpp)

extern "C" MAKEDLL_API int TestArrayOfInts( int* pArray, int size )
{
int result = 0;

for( int i = 0; i < size; i++ )
{
result += pArray[ i ];
pArray[ i ] += 100;
}
return result;
}
//**********************************
C++作成dllソース(makedll.h)

#ifdef MAKEDLL_EXPORTS
#define MAKEDLL_API __declspec(dllexport)
#else
#define MAKEDLL_API __declspec(dllimport)
#endif
extern "C" MAKEDLL_API int TestArrayOfInts( int* pArray, int size );

//**********************************
C++作成dllソース(makedll.def)
LIBRARY makedll.dll
EXPORTS
TestArrayOfInts PRIVATE

投稿日時 - 2011-01-10 23:51:58

QNo.6439372

すぐに回答ほしいです

質問者が選んだベストアンサー

DLL側から 少数を含む合計を返すなら

VB側の宣言を
Declare Function TestArrayOfDoubles Lib "makedll.dll" ( _
<[In](), Out()> ByVal myArray() As Double, ByVal size As Integer) As Double
に変更

DLL側を

extern "C" MAKEDLL_API double __stdcall TestArrayOfDoubles( double* pArray, int size )
{
double result = 0;

といった具合ですよ

投稿日時 - 2011-01-11 15:04:12

お礼

有難うございました。
無事動作いたしました。

投稿日時 - 2011-01-12 00:56:21

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.3

このソースですと C++側の呼び出し規約が __cdeclになってしまうので スタックの使い方が違うと思います

関数宣言/実装を __stdcallにして見ましょう

C++作成dllソース(makedll.cpp)

extern "C" MAKEDLL_API int __stdcall TestArrayOfDoubles( double* pArray, int size )
{
int result = 0;

for( int i = 0; i < size; i++ )


// makedll.h
extern "C" MAKEDLL_API int __stdcall TestArrayOfDoubles( double* pArray, int size );

投稿日時 - 2011-01-11 04:28:29

補足

上記の様に変更しましたが、正しい値が返って来ませんでした。

投稿日時 - 2011-01-11 11:56:30

ANo.2

Double 型を配列で渡し、合計を返す関数の例です。

C++ DLL 側
stdafx.h
==============================================
#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN // Windows ヘッダーから使用されていない部分を除外します。

#include <windows.h>
#include <oaidl.h>
==============================================

DoubleArrayTest.cpp
==============================================
#include "stdafx.h"

extern "C" __declspec(dllexport) double SumOfDoubleArray( LPSAFEARRAY *ppsa, int size )
{
double *pda;
double sum = 0.0;

SafeArrayAccessData( *ppsa, (void**)&pda );
for( int i = 0; i < size; i++ ) {
sum += *pda;
pda++;
}
SafeArrayUnaccessData( *ppsa );

return sum;
}
==============================================

VB 側
==============================================
Imports System.Runtime.InteropServices

Public Class Form1

Private Declare Function SumOfDoubleArray Lib "DoubleArrayTest.dll" _
(<MarshalAs(UnmanagedType.SafeArray)> ByRef array() As Double, ByVal count As Integer) As Double

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim da() As Double = {1.2, 3.4, 5.6}

Dim sum As Double = SumOfDoubleArray(da, da.Length)
Debug.WriteLine(sum)

End Sub
End Class
==============================================

投稿日時 - 2011-01-11 04:16:17

補足

回答ありがとうございます。
上記のソースで動作確認したところ、
PInvokStackImbalance が検出されました。
PInvokeシグネチャがアンネージターゲット シグネチャ一致していないことが原因と出ます。
また、stdafx.h内の記述のtargetver.hの参照ができません。

投稿日時 - 2011-01-11 11:49:10

ANo.1

単純な置き換えでうまくいきませんか?

当方の環境では IntegerをDoubleに置き換えただけで 期待通りの動作になっていますよ

'arrays.vb
Declare Function TestArrayOfDoubles Lib "makedll.dll" ( _
<[In](), Out()> ByVal myArray() As Double, ByVal size As Integer) As Integer

Dim array1(9) As Double

Dim sum1 As Integer = NativeMethods.TestArrayOfDoubles(array1, array1.Length)

// makedll.cpp
extern "C" MAKEDLL_API int TestArrayOfDoubles( double* pArray, int size )
{
  int result = 0;

  for( int i = 0; i < size; i++ )
  {
    result += (int)pArray[ i ];
    pArray[ i ] += 100;
  }
  return result;
}

// makedll.h
extern "C" MAKEDLL_API int TestArrayOfDoubles( int* pArray, int size );

// mamkedll.def
TestArrayOfDoubles PRIVATE

といった変更です

2次元(以上の)配列や 多段配列の場合は SafeArray経由にしないと操作がうまくないのですが
単純な1次元配列なら doubleやSingle(float)やInteger(int)ならポインタで受けてやればいいと思います

sum1の計算がうまく出来ないのか
DLLへ飛んでいってかえってきたときの arrayの内容が期待したとおりではないのか

何がまずいのかを明記しましょう

投稿日時 - 2011-01-11 04:03:21

補足

捕捉致します。
1.1などの小数点を含む値が計算できないということです。
上記の様に変更致しましたが、同様の結果でした。

投稿日時 - 2011-01-11 11:52:29

あなたにオススメの質問