将引用DLL的通道从VBA转换为VB.NET

时间:2018-01-24 09:39:56

标签: c++ vb.net vba interop dllimport

我试图重写一段包含从VBA到VB.NET的C ++ dll调用的代码。
特别是有一个C ++函数,我在dll中调用,对float的几个二维数组执行某些操作:

int __stdcall FindPolarization(int PointsTheta, int PointsPhi, float* Real1, float* Imag1 = nullptr)
{
    double Max[4] = { -999, -999, -999, -999 };         // Max values
    long MaxPos[4][2] = { -999, -999,                   // Max Theta and Max Phi
        -999, -999,
        -999, -999,
        -999, -999 };
    float* Pointers[4][2];
    double DeltaTheta = static_cast<double>(180.0 / PointsTheta);
    double DeltaPhi = static_cast<double>(360.0 / PointsPhi);
    vector<vector<vector<double>>> Ampl;

    // Setup
    Pointers[0][0] = Real1;
    Pointers[0][1] = Imag1;
    Pointers[1][0] = Real2;
    Pointers[1][1] = Imag2;
    Pointers[2][0] = Real3;
    Pointers[2][1] = Imag3;
    Pointers[3][0] = Real4;
    Pointers[3][1] = Imag4;
    if (Real3 != nullptr && Real4 != nullptr && Imag3 != nullptr && Imag4 != nullptr)
    {
        Ampl.resize(4, vector<vector<double>>(PointsTheta + 1, vector<double>(PointsPhi, 0)));
        Real3 = nullptr; Imag3 = nullptr; Real4 = nullptr; Imag4 = nullptr;
    }
    else
    {
        Ampl.resize(2, vector<vector<double>>(PointsTheta + 1, vector<double>(PointsPhi, 0)));
    }
    Real1 = nullptr; Imag1 = nullptr; Real2 = nullptr; Imag2 = nullptr;

    // Coordinates transformation + Maximum storage
    Concurrency::parallel_for(0, PointsPhi, [&](int j)
    {

        double PhiRad = j * DeltaPhi * Deg2Rad;
        double CosPhi = cos(PhiRad);
        double SinPhi = sin(PhiRad);
        int ind;
        pair<double, double> AmplCoCr;

        for (int i = 0; i <= PointsTheta; i++)
        {

            ind = j * (PointsTheta + 1) + i;

            for (int k = 0; k < static_cast<int>(Ampl.size()); k = k + 2)
            {
                AmplCoCr = AmplCalc(ind, Pointers[k][0], Pointers[k][1], Pointers[k + 1][0], Pointers[k + 1][1], CosPhi, SinPhi);
                Ampl[k][i][j] = AmplCoCr.first;
                Ampl[k + 1][i][j] = AmplCoCr.second;

                if (Ampl[k][i][j] > Max[k])
                {
                    Max[k] = Ampl[k][i][j];
                    MaxPos[k][0] = i;
                    MaxPos[k][1] = j;
                }
                if (Ampl[k + 1][i][j] > Max[k + 1])
                {
                    Max[k + 1] = Ampl[k + 1][i][j];
                    MaxPos[k + 1][0] = i;
                    MaxPos[k + 1][1] = j;
                }
            }
        }

    });

    double A = max(max(Max[0], Max[1]), max(Max[2], Max[3]));
    if (A > Max[1] && A > Max[2] && A > Max[3]) return 45;
    else if (A > Max[0] && A > Max[2] && A > Max[3]) return 135;
    else if (A > Max[0] && A > Max[1] && A > Max[3]) return 90;
    return 0; // else if (A > Max[0] && A > Max[1] && A > Max[2]) 

}


pair<double, double> AmplCalc(int index, float* RealCo, float* ImagCo, float* RealCr, float* ImagCr, double CosPhi, double SinPhi)
{
    double A, B;

    const double RealCoij = static_cast<double>(RealCo[index]);
    const double RealCrij = static_cast<double>(RealCr[index]);
    const double ImagCoij = static_cast<double>(ImagCo[index]);
    const double ImagCrij = static_cast<double>(ImagCr[index]);

    A = RealCoij * CosPhi + RealCrij * SinPhi;
    B = ImagCoij * CosPhi + ImagCrij * SinPhi;
    double Co = 10 * log10(A * A + B * B);

    A = (RealCoij * SinPhi * (-1) + RealCrij * CosPhi);
    B = (ImagCoij * SinPhi * (-1) + ImagCrij * CosPhi);
    double Cr = 10 * log10(A * A + B * B);

    return make_pair(Co, Cr);
}

在VBA环境中导入的内容为:

Private Declare Function FindPolarization Lib "EvalFunc.dll" (ByVal PointsTheta As Long, ByVal PointsPhi As Long, ByRef RealLev1 As Single, ByRef ImagLev1 As Single = 0) As Long

并通过以下代码调用:

Dim RealLev1() As Single, ImagLev1() As Single
Dim PolMax As Long, FFThetaPoints As Long, FFPhiPoints As Long

' Arrays are filled here through a function that determines their dimensions and values
FFThetaPoints = UBound(RealLev1, 1)
FFPhiPoints = UBound(RealLev1, 2)
PolMax = FindPolarization(FFThetaPoints, FFPhiPoints, RealLev1(0, 0), ImagLev1(0, 0))

这适用于VBA,但我一直试图将其转换为VB.NET并且失败了。

如果我无法更改dll中的C ++代码,我已停止使用以下代码。
该函数的导入如下:

 <DllImport("myDll.dll", SetLastError:=True, CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.StdCall)> _

Public Shared Function FindPolarization(ByVal PointsTheta As Integer, ByVal PointsPhi As Integer, ByRef RealLev1 As Single, _
Optional ByRef ImagLev1 As Single = Nothing) As Integer
End Function

调用它的代码是:

Dim FFThetaPoints As Integer, FFPhiPoints As Integer, PolMax As Integer
Dim RealLev1(,) As Single = Array.CreateInstance(GetType(Single), 1, 1)
Dim ImagLev1(,) As Single = Array.CreateInstance(GetType(Single), 1, 1)

FFThetaPoints = UBound(RealLev1, 1)
FFPhiPoints = UBound(RealLev1, 2)
PolMax = ImportDll.FindPolarization(FFThetaPoints, FFPhiPoints, RealLev1(0, 0), ImagLev1(0, 0))

现在,这些数组是System.Array类型,因为需要它们的特定功能。

虽然在VBA中我得到了一些结果,但在VB.NET中我获得了其他结果。我认为这与我如何声明Single数组有关,但我不确定。

我做错了什么?

1 个答案:

答案 0 :(得分:0)

我必须在这里给予@Craig所有的功劳。 VBA和VB.NET确实有不同的矩阵寻址逻辑(列主要与行主要),因此我不得不转换所有2D数组,而无需交换FFThetaPointsFFPhiPoints

值得一提的是,我尝试使用Excel.Application Worksheetfunction.Transpose方法,该方法无效。所以我必须编写自己的代码来转置矩阵。