在VB之间传递数组.. NET和vc++
Pass arrays between VB.NET and VC++
我已经编写了一个函数来计算平面文件结构中变量(风险)的相关矩阵。即RiskID | Year | Amount
我已经写了这个函数,因为我能找到的库例程需要矩阵输入。也就是说,RiskID作为第2个维度,year作为第1个维度,amount作为实际的数组值。矩阵需要是完整的,因为零值也必须包括在内,因此对于稀疏填充的非零数据-这会导致浪费迭代,可以绕过。例程依赖于首先按Year (asc)然后按RiskID (asc)
排序的数据。我已经在c++中编写了例程(为了速度),将其编译为dll并在VB.NET中引用。我需要传递3个数组(每个头一个),并返回一个二维数组回到VB.NET。我想我是作弊了,传递了3个单独的一维数组而不是二维数组,但这就对了。我将发布完整的c++例程,因为如果其他人寻求做类似的事情,可能会发现它很有用。如果以前没有人这样做过,我会很惊讶,但我就是找不到。
我缺乏互操作知识来正确地实现这一点,并且到处搜索都找不到。只要我能锻炼,我可能需要使用SAFEARRAY ?或者有快速解决这个问题的方法吗?或者SAFEARRAY是小菜一碟。无论哪种方式,一个例子都会很有帮助。
另外,作为旁注-我确信内存管理是失败的地方?
这是Visual c++ (VS2013)
头文件#ifndef CorrelLib_EXPORTS
#define CorrelLib_API __declspec(dllexport)
#else
#define CorrelLib_API __declspec(dllimport)
#endif
// Returns correlation matrix for values in flat file
extern "C" CorrelLib_API double** __stdcall CalcMatrix(int* Risk, int* Year, double* Loss, const int& RowNo, const int& RiskNo, const int& NoSimYear);
CPP文件#include "stdafx.h"
#include "CorrelLib.h"
#include <memory>
#include <ctime>
using namespace std;
extern "C" CorrelLib_API double** __stdcall CalcMatrix(int* Risk, int* Year, double* Loss, const int& RowNo, const int& RiskNo, const int& NoSimYear)
{
int a, b;
int i, j, k;
int YearCount, MissingYears;
int RowTrack;
//Relies on Year and Risk being sorted in ascending order in those respective orders Year asc, Risk asc
double *RiskTrack = new double[RiskNo](); //array of pointers?
int *RiskTrackBool = new int[RiskNo](); //() sets inital values to zero
double *RiskAvg = new double[RiskNo]();
double *RiskSD = new double[RiskNo]();
//Create 2d array to hold results 'array of pointers to 1D arrays of doubles'
double** Res = new double*[RiskNo];
for (i = 0; i < RiskNo; ++i)
{
Res[i] = new double[RiskNo](); //()sets initial values to zero
}
//calculate average
for (i = 0; i < RowNo; i++)
{
a = Risk[i];
RiskAvg[a] = RiskAvg[a] + Loss[i];
}
for (i = 0; i < RiskNo; i++)
{
RiskAvg[i] = RiskAvg[i] / NoSimYear;
}
//Enter Main Loop
YearCount = 0;
i = 0; //start at first row
do {
YearCount = YearCount + 1;
a = Risk[i];
RiskTrack[a] = Loss[i] - RiskAvg[a];
RiskTrackBool[a] = 1;
j = i + 1;
do
{
if (Year[j] != Year[i])
{
break;
}
b = (int)Risk[j];
RiskTrack[b] = Loss[j] - RiskAvg[b];
RiskTrackBool[b] = 1;
j = j + 1;
} while (j < RowNo);
RowTrack = j;
//check through RiskTrack and if no entry set to 0 - avg
for (j = 0; j < RiskNo; j++)
{
if (RiskTrackBool[j] == 0)
{
RiskTrack[j] = -1.0 * RiskAvg[j];
RiskTrackBool[j] = 1;
}
}
//Now loop through and perform calcs
for (j = 0; j < RiskNo; j++)
{
//SD
RiskSD[j] = RiskSD[j] + RiskTrack[j] * RiskTrack[j];
//Covar
for (k = j + 1; k < RiskNo; k++)
{
Res[j][k] = Res[j][k] + RiskTrack[j] * RiskTrack[k];
}
}
//Reset RiskTrack
for (k = 0; k<RiskNo; k++)
{
RiskTrack[k] = 0.0;
RiskTrackBool[k] = 0;
}
i = RowTrack;
} while (i < RowNo);
//Account For Missing Years
MissingYears = NoSimYear - YearCount;
for (i = 0; i < RiskNo; i++)
{
//SD
RiskSD[i] = RiskSD[i] + MissingYears * RiskAvg[i] * RiskAvg[i];
//Covar
for (j = i + 1; j < RiskNo; j++)
{
Res[i][j] = Res[i][j] + MissingYears * RiskAvg[i] * RiskAvg[j];
}
}
//Covariance Matrix
for (i = 0; i < RiskNo; i++)
{
//SD
RiskSD[i] = sqrt(RiskSD[i] / (NoSimYear - 1));
if (RiskSD[i] == 0.0)
{
RiskSD[i] = 1.0;
}
//Covar
for (j = i + 1; j < RiskNo; j++)
{
Res[i][j] = Res[i][j] / (NoSimYear - 1);
}
}
//Correlation Matrix
for (i = 0; i < RiskNo; i++)
{
Res[i][i] = 1.0;
for (j = i + 1; j < RiskNo; j++)
{
Res[i][j] = Res[i][j] / (RiskSD[i] * RiskSD[j]);
}
}
//Clean up
delete[] RiskTrack;
delete[] RiskTrackBool;
delete[] RiskAvg;
delete[] RiskSD;
//Return Array
return Res;
}
Def文件LIBRARY CorrelLib
EXPORTS
CalcMatrix
VB。
我创建了一个简单的winform,带有一个触发下面代码的按钮。我希望链接到dll,传递数组并接收结果作为2d数组。
Imports System
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("CorrelLib.dll", EntryPoint:="CalcMatrix", CallingConvention:=CallingConvention.StdCall)> _
Public Shared Function CorrelMatrix2(ByRef Risk_FE As Integer, ByRef Year_FE As Integer, ByRef Loss_FE As Double, _
ByRef RowNo As Long, ByRef RiskNo As Long, ByRef NoSimYear As Long) As Double(,)
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim i As Integer, j As Integer
Dim Risk() As Long, Year() As Long, Loss() As Double
Dim NoRisks As Long, NoSimYear As Long, NoRows As Long
Dim counter As Long
Dim Result(,) As Double
NoRisks = 50
NoSimYear = 10000
NoRows = NoRisks * NoSimYear
ReDim Risk(0 To NoRows - 1), Year(0 To NoRows - 1), Loss(0 To NoRows - 1)
counter = 0
For i = 1 To NoSimYear
For j = 1 To NoRisks
Risk(counter) = j
Year(counter) = i
Loss(counter) = CDbl(Math.Floor((1000000 - 1 + 1) * Rnd())) + 1
counter = counter + 1
Next j
Next i
Dim dllDirectory As String = "C:UsersDocumentsVisual Studio 2013ProjectsCorrelLibTestForm"
Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";" + dllDirectory)
Result = CorrelMatrix2(Risk(1), Year(1), Loss(1), NoRows, NoRisks, NoSimYear)
End Sub
End Class
当前错误信息
类型为>'System.Runtime.InteropServices. '的未处理异常。MarshalDirectiveException'发生在>CorrelLibTestForm.exe
附加信息:无法封送"返回值":无效的>托管/非托管类型组合。
指向指针的double **
指针是而不是,与vb中的二维数组相同。最好的方法是只返回一个指针:
double *pdbl;
pdbl = &res[0][0];
return pdbl; //pdbl points to the first element
在vb中,您使用IntPtr
来获取指针:
Dim Result As IntPtr = Marshal.AllocHGlobal(4)
Dim dbl As Double
Result = CorrelMatrix2(Risk(1), Year(1), Loss(1), NoRows, NoRisks, NoSimYear)
//derefference the double pointer, i(integer) is actually the index in the array of doubles
dbl = CType(Marshal.PtrToStructure(IntPtr.Add(Result, i * 8), GetType(Double)), Double)
c++函数中的res
数组需要是公共的,以便在函数返回后分配给它的内存有效。
- 参考资源文件VC++中的$(SolutionDir)
- VC++本机单元测试,找不到调试符号
- 在 C++/CLI 中将 .NET 事件从一个 DLL 引发到另一个 DLL
- 如何在 64 位 vb.net Windows 应用程序中引用 32 位 dll
- 加载与引用 .NET DLL 位于同一文件夹中的引用的 .NET DLL 时"Not found"异常
- 是否可以在Linux上使用.Net Core 3.1创建C++/CLI代码的C#DLL
- 在这里,当我们比较 if(vc[i]==vc1[i]) 时,它是向量数组. 实际上比较的值是多少,
- Poco::Net::FTPClientSession 在 open() 方法上挂起 129 秒,如果 ftp 主机不存
- VS2015 中的 VC++ 目录
- C++ DLL(不是 CLI)是否可以调用 .NET Core 3.0 委托?
- System.AccessViolationException:shared_ptr C# .NET 和 C++ 应用程
- VS2015/VC++ 在新类模板中禁用默认 #include "stdafx.h"
- C++/CLI targetting .NET Core 3.1
- 获取传递给子模块(C#.NET dll)中的主模块(VC++ exe)的参数
- VC++ VB.NET 代码转换
- 如何在VC++中不使用.NET Framework来确定特定事件日志是否存在
- 从CC.Net记录VC++9(Visual Studio 2008)中的项目生成时间
- 在VB之间传递数组.. NET和vc++
- vc.net:无法设置双精度变量的值
- 如何在 VC++/CLI 中实现 VB.net 中定义的接口