将对 DLL 的引用从 VBA 翻译成 VB.NET
Translating the passage of a reference to a DLL from VBA to VB.NET
我正在尝试重写一段代码,其中包括从 VBA 到 VB.NET 的 C++ dll 调用。
特别是我在 dll 中调用了一个 C++ 函数,它对 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
数组的方式有关,但我不确定。
我做错了什么?
我必须在这里把所有的功劳都归功于@Craig。
VBA 和 VB.NET 确实有不同的矩阵寻址逻辑(主要列与行主要),所以我不得不转置所有二维数组,而不交换 FFThetaPoints
和 FFPhiPoints
。
值得一提的是,我尝试使用Excel.Application
Worksheetfunction.Transpose
方法,但没有达到预期效果。所以我不得不自己写一段代码来转置矩阵。
我正在尝试重写一段代码,其中包括从 VBA 到 VB.NET 的 C++ dll 调用。
特别是我在 dll 中调用了一个 C++ 函数,它对 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
数组的方式有关,但我不确定。
我做错了什么?
我必须在这里把所有的功劳都归功于@Craig。
VBA 和 VB.NET 确实有不同的矩阵寻址逻辑(主要列与行主要),所以我不得不转置所有二维数组,而不交换 FFThetaPoints
和 FFPhiPoints
。
值得一提的是,我尝试使用Excel.Application
Worksheetfunction.Transpose
方法,但没有达到预期效果。所以我不得不自己写一段代码来转置矩阵。