こんにちは、c# から構造体の c++ 配列にアクセスしようとしています。構造体自体にも、文字列の配列と文字列が含まれています。詳細は以下です。それは機能していません..クラッシュはしませんが、データを転送しません (たとえば、配列で null を取得し、構造体/クラスの numberOfRows 整数で乱数を取得します)。コード リストの最後にある私のコメントを参照してください。助言がありますか?
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 は、matrix[0].numberOfRows を返すだけなので 1 を返す必要がありますが、実際には巨大な数を返します。
また、コメント化されていない場合の getMatrix 呼び出しも機能せず、クラッシュせずに実行されますが、配列のすべての要素が空になります (getMatrix がそれらに入力するはずのデータが入力されていません)。