アプリ版:「スタンプのみでお礼する」機能のリリースについて

プログラム初心者です。
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

A 回答 (4件)

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;

といった具合ですよ
    • good
    • 0
この回答へのお礼

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

お礼日時:2011/01/12 00:56

このソースですと 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 11:56
    • good
    • 0

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
==============================================

この回答への補足

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

補足日時:2011/01/11 11:49
    • good
    • 0

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



当方の環境では 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の内容が期待したとおりではないのか

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

この回答への補足

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

補足日時:2011/01/11 11:52
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!