[제품종류] IEC667Lite
[개발환경] Visual Studio 2008 C#
=============== 질 문 ===============설정 정보 저장을 위해 구조체 선언을 하고, SmartFile을 이용해 구조체 저장방법으로 진행하려고 합니다.
구조체 선언은 아래와 같이 진행하였습니다.
구조체 내 {("3종류 데이터 * 10개씩"을 갖는 구조체)를 다시 "10개"}를 갖는 배열형 멤버가 있습니다.
[StructLayout(LayoutKind.Sequential)]
public struct FINSTALL
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public double[] Set1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] Set2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public byte[] Set3;
}
public struct FLIMIT
{
public double Min;
public double Max;
}
public struct FSETUP
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public FINSTALL[] Install;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public FLIMIT[] Limit;
public double Rbase;
public double Cbase;
public double Hbase;
public FSETUP(double ARbase, double ACbase, double AHbase)
{
Install = new FINSTALL[10];
for (int p = 0; p < 10; p++)
{
Install[p].Set1 = new double[10];
Install[p].Set2 = new byte[10];
Install[p].Set3 = new byte[10];
for (int s = 0; s < 10; s+)
{
Install[p].Set1[s] = 0.5;
Install[p].Set2[s] = 1;
Install[p].Set3[s] = 1;
}
}
Limit = new FLIMIT[3];
for (int m = 0; m < 3; m++)
{
Limit[m].Min = 0.0;
Limit[m].Max = 0.0;
}
Rbase = ARbase;
Cbase = ACbase;
Hbase = AHbase;
}
}
아래와 같이 파일을 불러올 때,
Setup = (FSETUP)SetupFile.StructType.Read(); 구문에서
NullReferenceException이 발생하는데 이유를 못 찾겠습니다.
SetupFile = new SmartX.SmartFile();
SetupFile.FilePathName = SETUP_FILE_PATH;
SetupFileOpenStatus = false;
Setup = new FSETUP(0.0, 0.0, 0.0);
if (SetupFile.Open())
{
SetupFile.StructType.SetStructType(typeof(FSETUP));
/*exception 발생 위치*/ Setup = (FSETUP)SetupFile.StructType.Read();
SetupFileOpenStatus = true;
}
else
{
SmartX.SmartMessageBox.Show("Failed to open settings file");
}
그리고, 아래와 같이 파일을 저장하고 있으며, 파일생성은 이루어지지만 정상적인 데이터를 볼 수 없습니다.
SetupFile.StructType.SetStructType(typeof(FSETUP));
SetupFileOpenStatus = true;
for (int p = 0; p < 10; p++)
{
for (int s = 0; s < 10; s+)
{
Setup.Install[p].Set1[s] = 0.0;
Setup.Install[p].Set2[s] = 0;
Setup.Install[p].Set3[s] = 0;
}
}
for (int m = 0; m < 3; m++)
{
Setup.Limit[m].Min = 0.4;
Setup.Limit[m].Max = 2.1;
}
Setup.Rbase = 0.0;
Setup.Cbase = 1.0;
Setup.Hbase = 0.0;
SetupFile.StructType.Write(Setup);
배열을 갖는 구조체를 smartfile을 통해 저장하고 불러오는 방식을 알고 싶습니다.
감사합니다.
=============== 답 변 ===============
안녕하세요.
문의주신 내용을 확인해본 결과 현재 구조체 안에 구조체 배열을 생성하여 사용하고 계신 것을 확인하였습니다.
이 때 문제가 되는 부분은 구조체 안에 [구조체 배열]을 사용하는 것이 문제가 됩니다. 구조체 배열의 경우 마샬 정보에서 크기를
정의할 수 없기 때문에 사용이 불가능합니다.
[구조체] : 사용 가능
[구조체 내부에 구조체] : 사용 가능
[구조체 내부에 구조체 배열] : 사용 불가능
[구조체 배열] : 사용 불가능
또한 하나의 구조체에서 2차원 배열을 사용하여 사용하는 방법으로 테스트를 진행해봤지만 마샬 정보를 입력할 때 2차원 배열의
[X, Y]의 X크기, Y크기를 개별로 정의할 수 없기 때문에 File Write는 정상적으로 써지지만 File Read 시 X, Y의 크기가 명확하지 않아
배열이 Index가 깨지게 되어 불가능합니다.
그렇기 때문에 해결 방법으로는 하나의 구조체에서 1차원 배열을 사용하여 정의하되 Getter, Setter 방식을 사용하여 2차원 적으로
데이터에 접근하는 방법이 있습니다. 자세한 내용은 아래의 예시 코드를 참고하시기 바랍니다.
[예시 코드]
public struct FSETUP
{
// 배열의 크기를 10X10 즉, 100으로 설정합니다.
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public double[] Set1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public byte[] Set2;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
public byte[] Set3;
public double Rbase;
public double Cbase;
public double Hbase;
public FSETUP(double ARbase, double ACbase, double AHbase)
{
Set1 = new double[10 * 10];
Set2 = new byte[10 * 10];
Set3 = new byte[10 * 10];
Rbase = ARbase;
Cbase = ACbase;
Hbase = AHbase;
}
// 배열의 데이터를 iIndex와 jIndex로 2차원 배열과 같이 접근하여 Value를 설정합니다.
public void SSet1(int iIndex, int jIndex, double dValue)
{
Set1[(iIndex * 10) + jIndex] = dValue;
}
// 파일에서 읽어온 데이터를 iIndex와 jIndex로 2차원 배열과 같이 접근하여 가져옵니다.
public double GSet1(int iIndex, int jIndex)
{
return Set1[(iIndex * 10) + jIndex];
}
public void SSet2(int iIndex, int jIndex, byte bValue)
{
Set2[(iIndex * 10) + jIndex] = bValue;
}
public byte GSet2(int iIndex, int jIndex)
{
return Set2[(iIndex * 10) + jIndex];
}
public void SSet3(int iIndex, int jIndex, byte bValue)
{
Set3[(iIndex * 10) + jIndex] = bValue;
}
public byte GSet3(int iIndex, int jIndex)
{
return Set3[(iIndex * 10) + jIndex];
}
}
private void FileWrite()
{
FSETUP exStruct = new FSETUP(0.0, 0.0, 0.0);
for (int p = 0; p < 10; p++)
{
for (int s = 0; s < 10; s++)
{
// [p, s] 위치에 Value를 설정합니다.
exStruct.SSet1(p, s, (double)(s + 100));
exStruct.SSet2(p, s, (byte)s);
exStruct.SSet3(p, s, (byte)(s + 10));
}
}
// 설정이 완료된 구조체를 File에 Write 합니다.
smartFile1.StructType.Write(exStruct);
smartFile1.Close();
}
private void FileRead()
{
FSETUP exStruct;
exStruct = (FSETUP)smartFile1.StructType.Read();
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
// 구조체 파일에서 읽어온 데이터에서 [i, j] 위치의 Value를 ListBox에 출력합니다.
smartListBox1.AddItem(exStruct.GSet1(i, j).ToString());
}
}
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
smartListBox1.AddItem(exStruct.GSet2(i, j).ToString());
}
}
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
smartListBox1.AddItem(exStruct.GSet3(i, j).ToString());
}
}
}
감사합니다.