gpt4 book ai didi

c# - 编码包含字符串数组的结构数组

转载 作者:太空狗 更新时间:2023-10-29 23:07:49 27 4
gpt4 key购买 nike

您好,我正在尝试从 C# 访问结构的 C++ 数组。该结构本身还包含一个字符串数组和一个字符串。详情如下。它不工作.. 不会崩溃但不会传输数据(例如,在数组中获取空​​值,并在结构/类的 numberOfRows 整数中获取随机数)。请参阅代码 list 末尾的评论。有什么建议吗?

c++ cppClassLib.cpp

// This is the main DLL file.



#include "stdafx.h"
#include <Objbase.h>

#include "cppClassLib.h"

#include <string.h>
//#include <malloc.h>

namespace cppClassLib {

/*
http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
http://stackoverflow.com/questions/9093292/use-a-c-library-from-c-sharp-code
http://stackoverflow.com/questions/5671658/what-does-invalid-managed-unmanaged-type-combination-mean
http://stackoverflow.com/questions/2338146/returning-pointers-from-unmanaged-to-managed-code
CoTaskMemAlloc http://msdn.microsoft.com/en-us/library/windows/desktop/ms692727%28v=vs.85%29.aspx
*/

char *createStr(char *input)
{
int len = strlen(input)+1;

// can't use malloc because it needs to
// be accessible from another process.
// can't use CoTaskMemAlloc because get an
// error when trying to link, not found.
//char *newStr = (char *)CoTaskMemAlloc(len);
//char *newStr = (char *)malloc(len);

char *newStr = (char *)GlobalAlloc(GPTR,len);
//char* newStr = new char[len];
strcpy_s(newStr, len, input);
return newStr;
}

int Class1::getMatrixNumberOfRowsInColumnZero(int maxColumns, Class1::columnT *matrix)
{
if (maxColumns < 1) {
return 0;
}
return matrix[0].numberOfRows;
}

int Class1::getMatrix(int maxColumns, Class1::columnT *matrix)
{
if (maxColumns < 2) {
return 0;
}
int numberOfColumns = 2;

//Class1::columnT *column0 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
Class1::columnT *column0 = &(matrix[0]);
column0->columnName = createStr("Col0");
int numRows = 2;
column0->numberOfRows = numRows;
char **rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
rows[0] = createStr("C0R0");
rows[1] = createStr("C0R1");
column0->rows = rows;

Class1::columnT *column1 = &(matrix[1]);
//Class1::columnT *column1 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
column1->columnName = createStr("Col1");
numRows = 2;
column1->numberOfRows = numRows;
rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
rows[0] = createStr("C1R0");
rows[1] = createStr("C1R1");
column1->rows = rows;

//matrix[0]=column0;
//matrix[1]=column1;
//(matrix[0])->columnName = createStr("Test0");

return numberOfColumns; // 2
}

int Class1::getInt(void)
{
return 1234;
}

char* Class1::getHi(void)
{
//char *result = createStr("Hello");
//return result;
//return createStr("hello");
return createStr("hello");
}

char** Class1::getHeaderList(void)
{
char** list;
list = (char **)GlobalAlloc(GPTR,sizeof(char *)*2);
list[0]=createStr("test1");
list[1]="test2";
return list;
}

int Class1::getHeaderListTwo(int maxsize, char ***result)
{
char** list;
int len = 2;
if (maxsize < len) {
return NULL;
}
list = (char **)GlobalAlloc(GPTR,sizeof(char *)*maxsize);
list[0]=createStr("test01");
list[1]="test02";
for (int i=2; i<maxsize; ++i) {
list[i]="";
}
*result = list;
return len;
}

char* Class1::getHi2(void)
{
return "Hi";
}

char* Class1::getHi3(void)
{
return "Hi!";
}

void Class1::getData(int *totalColumns,
char** headers[2],
char** items[2][3])
{
*totalColumns = 2;
*headers[0]=createStr("Testing");
*headers[1]=createStr("Pets");
*items[0][0]=createStr("test1");
*items[0][1]=createStr("test2");
*items[0][2]=createStr("test3");
*items[1][0]=createStr("Cats");
*items[1][1]=createStr("Dogs");
*items[1][2]=createStr("Fish");
}

}

c++ cppClassLib.h

    // cppClassLib.h

#pragma once

using namespace System;

#define DllExport __declspec( dllexport )

// http://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx

namespace cppClassLib {

public class Class1 {
public:
struct columnT {
int numberOfRows;
char **rows;
char *columnName;
};
static DllExport int getMatrix(int maxColumns, columnT *matrix);
static DllExport int getMatrixNumberOfRowsInColumnZero(int maxColumns, columnT *matrix);
static DllExport void getData(int *totalColumns,
char** headers[2],
char** items[2][3]);
static DllExport char *getHi(void);
static DllExport char *getHi2(void);
static DllExport char *getHi3(void);
static DllExport int getInt(void);
static DllExport char** getHeaderList(void);
static DllExport int getHeaderListTwo(int maxsize, char ***result);
};
}

c# Form1.cs

  using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;

/*

http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx
http://ondotnet.com/pub/a/dotnet/2002/03/18/customcontrols.html?page=2
http://www.codeproject.com/Articles/2995/The-Complete-Guide-to-C-Strings-Part-I-Win32-Chara
http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

*/

namespace listViewFromC
{
public partial class Form1 : Form
{
/*
[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getInt@Class1@cppClassLib@@QAEHXZ")]
public static extern int getInt();
*/

// get EntryPoint using
// "DLL Export Viewer" software

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHi2@Class1@cppClassLib@@SAPADXZ")]
public static extern String getHi2();

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHi@Class1@cppClassLib@@SAPADXZ")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string getHi();

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHeaderList@Class1@cppClassLib@@SAPAPADXZ")]
[return: MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPStr, SizeConst=2)]
public static extern String[] getHeaderList();

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHeaderListTwo@Class1@cppClassLib@@SAHHPAPAPAD@Z")]
public static extern int getHeaderListTwo(int maxsize,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 0)]
ref String[] result
);

[StructLayout(LayoutKind.Sequential)]
public class columnType
{
public int numberOfRows;
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.LPStr)]
public String[] rows;
[MarshalAs(UnmanagedType.LPStr)]
public String columnName;
}

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getMatrix@Class1@cppClassLib@@SAHHPAUcolumnT@12@@Z")]
public static extern int getMatrix(int maxColumns,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)]
columnType[] matrix);

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getMatrixNumberOfRowsInColumnZero@Class1@cppClassLib@@SAHHPAUcolumnT@12@@Z")]
public static extern int getMatrixNumberOfRowsInColumnZero(int maxColumns,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)]
columnType[] matrix);

/*
[DllImport("kernel32.dll")]
static extern IntPtr GlobalAlloc(uint uFlags, uint dwBytes);

const uint GMEM_FIXED = 0x0000;
const uint GMEM_ZEROINIT = 0x0040;
const uint GPTR = GMEM_FIXED | GMEM_ZEROINIT;
*/

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
//label1.Text = getInt().ToString();
label1.Text = getHi2();
listView1.Items.Clear();
listView1.Items.Add(label1.Text);
//listView1.
}

private void button2_Click(object sender, EventArgs e)
{
label1.Text = getHi();
}

private void button3_Click(object sender, EventArgs e)
{
const int maxsize = 2;
String[] headerList = new String[maxsize];
int len = getHeaderListTwo(maxsize, ref headerList);
MessageBox.Show("Got length " + headerList.Length+" ("+len+")");
label1.Text="";
for (int i = 0; i < headerList.Length; ++i)
{
if (headerList[i].Length>0)
{
label1.Text += headerList[i].ToString() + " // ";
}
else
{
label1.Text += " // ";
}
}
}

private void button4_Click(object sender, EventArgs e)
{
int maxColumns=5;
int numberOfColumns = 0;
columnType[] matrix = new columnType[maxColumns];
for (int i = 0; i < maxColumns; ++i)
{
matrix[i] = new columnType();
}
matrix[0].numberOfRows = 1; // pick something just to see if we can get it back
//uint sz = (uint)maxColumns*4;
//IntPtr matrixIP = GlobalAlloc(GPTR, sz);
//columnType[] matrix = matrixIP;

//IntPtr pointerArr = Marshal.AllocHGlobal(maxColumns*4);

//numberOfColumns = getMatrix(maxColumns, matrix);
label1.Text = getMatrixNumberOfRowsInColumnZero(maxColumns,matrix).ToString();

//label1.Text = matrix[0].columnName;
}
}
}

button1、button2 和 button3 单击事件工作正常,因此它表明某些 c++ 编码到 c# 的工作正常。 button4_click 不起作用。

label1.Text 应该返回 1,因为它只是返回 matrix[0].numberOfRows但实际上它返回了一些巨大的数字。

此外,如果未注释,getMatrix 调用也不起作用,它运行时不会崩溃,但数组的所有元素都为空(未填充 getMatrix 应该填充的数据)。

最佳答案

这是我的解决方案。这个解决方案的唯一怪癖是结构中需要固定长度的数组,我更喜欢可变长度的数组,但它不接受 LPArray 的 Marshall。也许这是不可能的。

我遇到的主要问题是我将其声明为类而不是结构。另一个问题是结构中的数组是 LPArray 非托管编码类型,尝试使用可变长度数组,但这没有用,因为它需要是 ByValArray(或 SafeArray)才能工作。


cpp类库.h

// cppClassLib.h

#pragma once

using namespace System;

#define DllExport __declspec( dllexport )

// http://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx

#define maxRowsCpp 100

namespace cppClassLib {

public class Class1 {
public:
struct columnT {
int numberOfRows;
char *rows[maxRowsCpp];
char *columnName;
};
struct columnT2 {
int numberOfRows;
};
static DllExport int __thiscall getMatrix(int maxColumns, int maxRows, columnT *matrix[]);
static DllExport int __thiscall getMatrixNumberOfRowsInColumnZero(int maxColumns, columnT matrix[]);
static DllExport int __thiscall getMatrixNumberOfRowsInColumnZero2(int maxColumns, columnT2 matrix[]);
static DllExport void getData(int *totalColumns,
char** headers[2],
char** items[2][3]);
static DllExport char *getHi(void);
static DllExport char *getHi2(void);
static DllExport char *getHi3(void);
static DllExport int getInt(void);
static DllExport char** getHeaderList(void);
static DllExport int getHeaderListTwo(int maxsize, char ***result);
};


cpp类库.cpp

// This is the main DLL file.

#include "stdafx.h"
#include <Objbase.h>

#include "cppClassLib.h"

#include <string.h>
//#include <malloc.h>

namespace cppClassLib {

/*
http://msdn.microsoft.com/en-us/magazine/cc164123.aspx
http://stackoverflow.com/questions/9093292/use-a-c-library-from-c-sharp-code
http://stackoverflow.com/questions/5671658/what-does-invalid-managed-unmanaged-type-combination-mean
http://stackoverflow.com/questions/2338146/returning-pointers-from-unmanaged-to-managed-code
CoTaskMemAlloc http://msdn.microsoft.com/en-us/library/windows/desktop/ms692727%28v=vs.85%29.aspx
*/

char *createStr(char *input)
{
int len = strlen(input)+1;

// can't use malloc because it needs to
// be accessible from another process.
// can't use CoTaskMemAlloc because get an
// error when trying to link, not found.
//char *newStr = (char *)CoTaskMemAlloc(len);
//char *newStr = (char *)malloc(len);

char *newStr = (char *)GlobalAlloc(GPTR,len);
//char* newStr = new char[len];
strcpy_s(newStr, len, input);
return newStr;
}

int Class1::getMatrixNumberOfRowsInColumnZero(int maxColumns, Class1::columnT matrix[])
{
if (maxColumns < 1) {
return 0;
}
return (matrix[0]).numberOfRows;
}

int Class1::getMatrixNumberOfRowsInColumnZero2(int maxColumns, Class1::columnT2 matrix[])
{
if (maxColumns < 1) {
return 0;
}
return (matrix[0]).numberOfRows;
}

int Class1::getMatrix(int maxColumns, int maxRows, Class1::columnT *matrix[])
{
// require at least able to have 2 rows and 2 columns
if ((maxColumns < 2) || (maxRows < 2)) {
return 0;
}
int numberOfColumns = 2;
int numberOfRows = 2;
//return matrix[0].columnName[0];

//Class1::columnT *column0 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
Class1::columnT *column0 = &(*matrix[0]);
column0->columnName = createStr("Col0");
column0->numberOfRows = numberOfRows;
//char **rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
column0->rows[0] = createStr("C0R0");
column0->rows[1] = createStr("C0R1");

Class1::columnT *column1 = &(*matrix[1]);
//Class1::columnT *column1 = (Class1::columnT *)GlobalAlloc(GPTR,sizeof(Class1::columnT));
column1->columnName = createStr("Col1");
column1->numberOfRows = numberOfRows;
//rows = (char **)GlobalAlloc(GPTR,sizeof(char *)*numRows);
column0->rows[0] = createStr("C1R0");
column0->rows[1] = createStr("C1R1");

return numberOfColumns;
}

int Class1::getInt(void)
{
return 1234;
}

char* Class1::getHi(void)
{
//char *result = createStr("Hello");
//return result;
//return createStr("hello");
return createStr("hello");
}

char** Class1::getHeaderList(void)
{
char** list;
list = (char **)GlobalAlloc(GPTR,sizeof(char *)*2);
list[0]=createStr("test1");
list[1]="test2";
return list;
}

int Class1::getHeaderListTwo(int maxsize, char ***result)
{
char** list;
int len = 2;
if (maxsize < len) {
return NULL;
}
list = (char **)GlobalAlloc(GPTR,sizeof(char *)*maxsize);
list[0]=createStr("test01");
list[1]="test02";
for (int i=2; i<maxsize; ++i) {
list[i]="";
}
*result = list;
return len;
}

char* Class1::getHi2(void)
{
return "Hi";
}

char* Class1::getHi3(void)
{
return "Hi!";
}

void Class1::getData(int *totalColumns,
char** headers[2],
char** items[2][3])
{
*totalColumns = 2;
*headers[0]=createStr("Testing");
*headers[1]=createStr("Pets");
*items[0][0]=createStr("test1");
*items[0][1]=createStr("test2");
*items[0][2]=createStr("test3");
*items[1][0]=createStr("Cats");
*items[1][1]=createStr("Dogs");
*items[1][2]=createStr("Fish");
}


c# Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Runtime.InteropServices;

/*

http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx
http://ondotnet.com/pub/a/dotnet/2002/03/18/customcontrols.html?page=2
http://www.codeproject.com/Articles/2995/The-Complete-Guide-to-C-Strings-Part-I-Win32-Chara
http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

*/

namespace listViewFromC
{
public partial class Form1 : Form
{
const int maxRows = 100;
/*
[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getInt@Class1@cppClassLib@@QAEHXZ")]
public static extern int getInt();
*/

// get EntryPoint using
// "DLL Export Viewer" software

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHi2@Class1@cppClassLib@@SAPADXZ")]
public static extern String getHi2();

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHi@Class1@cppClassLib@@SAPADXZ")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string getHi();

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHeaderList@Class1@cppClassLib@@SAPAPADXZ")]
[return: MarshalAs(UnmanagedType.LPArray,
ArraySubType=UnmanagedType.LPStr, SizeConst=2)]
public static extern String[] getHeaderList();

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?getHeaderListTwo@Class1@cppClassLib@@SAHHPAPAPAD@Z")]
public static extern int getHeaderListTwo(int maxsize,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.LPStr, SizeParamIndex = 0)]
ref String[] result
);

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct columnType
{
public int numberOfRows;
// note: can't marshal rows field as LPArray must be ByValArray or SafeArray
// for maximum of maxRows rows
[MarshalAs(UnmanagedType.ByValArray,
ArraySubType = UnmanagedType.LPStr,
SizeConst=maxRows)]
public String[] rows;
[MarshalAs(UnmanagedType.LPStr)]
public String columnName;
}

[StructLayout(LayoutKind.Sequential)]
public struct columnType2
{
public int numberOfRows;
}

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.ThisCall,
EntryPoint = "?getMatrix@Class1@cppClassLib@@SEHHHQAPAUcolumnT@12@@Z")]
public static extern int getMatrix(int maxColumns,
int maxRows,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.Struct, SizeParamIndex = 0)]
ref columnType[] matrix);

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.ThisCall,
EntryPoint = "?getMatrixNumberOfRowsInColumnZero@Class1@cppClassLib@@SEHHQAUcolumnT@12@@Z")]
public static extern int getMatrixNumberOfRowsInColumnZero(int maxColumns,
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.Struct,
SizeParamIndex = 0)]
columnType[] matrix);

[DllImport("cppClassLib.dll",
CallingConvention = CallingConvention.ThisCall,
EntryPoint = "?getMatrixNumberOfRowsInColumnZero2@Class1@cppClassLib@@SEHHQAUcolumnT2@12@@Z")]
public static extern int getMatrixNumberOfRowsInColumnZero2(int maxColumns,
[MarshalAs(UnmanagedType.LPArray,
SizeParamIndex = 0,
ArraySubType = UnmanagedType.Struct)]
columnType2[] matrix);

/*
[DllImport("kernel32.dll")]
static extern IntPtr GlobalAlloc(uint uFlags, uint dwBytes);

const uint GMEM_FIXED = 0x0000;
const uint GMEM_ZEROINIT = 0x0040;
const uint GPTR = GMEM_FIXED | GMEM_ZEROINIT;
*/

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
//label1.Text = getInt().ToString();
label1.Text = getHi2();
listView1.Items.Clear();
listView1.Items.Add(label1.Text);
//listView1.
}

private void button2_Click(object sender, EventArgs e)
{
label1.Text = getHi();
}

private void button3_Click(object sender, EventArgs e)
{
const int maxsize = 2;
String[] headerList = new String[maxsize];
int len = getHeaderListTwo(maxsize, ref headerList);
MessageBox.Show("Got length " + headerList.Length+" ("+len+")");
label1.Text="";
for (int i = 0; i < headerList.Length; ++i)
{
if (headerList[i].Length>0)
{
label1.Text += headerList[i].ToString() + " // ";
}
else
{
label1.Text += " // ";
}
}
}

private void button4_Click(object sender, EventArgs e)
{
int maxColumns=5;
int numberOfColumns = 0;
columnType[] matrix = new columnType[maxColumns];
for (int i = 0; i < maxColumns; ++i)
{
matrix[i] = new columnType();
}
matrix[0].numberOfRows = 1; // pick something just to see if we can get it back
matrix[0].columnName = "ABC";
// numberOfRows must be less than or equal to maxRows

columnType2[] matrix2 = new columnType2[maxColumns];
for (int i = 0; i < maxColumns; ++i)
{
matrix2[i] = new columnType2();
}
matrix2[0].numberOfRows = 1; // pick something just to see if we can get it back

//uint sz = (uint)maxColumns*4;
//IntPtr matrixIP = GlobalAlloc(GPTR, sz);
//columnType[] matrix = matrixIP;

//IntPtr pointerArr = Marshal.AllocHGlobal(maxColumns*4);

//int result = getMatrixNumberOfRowsInColumnZero(maxColumns,matrix);
//label1.Text = result.ToString();

numberOfColumns = getMatrix(maxColumns, maxRows, ref matrix);
label1.Text = matrix[0].columnName;

}
}
}

关于c# - 编码包含字符串数组的结构数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11490087/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com