.NET Forum / .NET Framework / Interop / June 2005
Marshaling 2-Dim Arrays
|
|
Thread rating:  |
rmacias - 10 Jun 2005 23:22 GMT I am currently writing a C# app replacing an old app written in VB6. Part of the app save it's structure contents to a binary file. The old VB6 app dumps the structure into the file via:
Put #Fnumb, , MyVB6Structure
It is critial for my app that I write to this binary file in the same format as the old VB6 app did because another VB6 will be reading the file generated by my new app.
Inside my C# app, I have the old VB6 structure defined as follows:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public class MyVB6StructureInCSharp { public float myfloat1; public int myInt1; [MarshalAs(UnmanagedType.SafeArray)] public bool[,] TwoDimArrayOfBool;
[MarshalAs(UnmanagedType.BStr, SizeConst = 255)] public string myString;
}//end of class TimingType1
During my save function, I am able to create an instance of this class and populate it with the appropiate data. I then want to take this class and then write it to a binary file (in the same format that VB6 does it). The approach I am using is that I want to take the class and convert it into an unmanaged array of bytes, and write this byte array to the binary file. I convert the class into an an array of bytes as follows:
private byte[] StructureToBytes(MyVB6StructureInCSharp myStruct) { int size; IntPtr p; byte[] ret;
//The line below generates an exception: //can not be marshaled as an unmanaged //structure; no meaningful size or offset can be //computed. size = Marshal.SizeOf(myStruct.GetType()); p = Marshal.AllocCoTaskMem(size);
try { Marshal.StructureToPtr(timingStruct, p, false);
//Copy the unmanaged structure pointer into an array of bytes. ret = new byte[size]; Marshal.Copy(p, ret, 0, size); } finally { //clean up our little mess. Marshal.FreeCoTaskMem(p); }
//return the bytes return ret;
}
When I perform the "size = Marshal.SizeOf(myStruct.GetType());" command I get an exception that tells me that it can not marshal the structure as an unmanaged structure becasue no size or offset can be determined. I have narrowed down the problem to be the 2 dimensional array of booleans that is defined in my class. It appears that the problem is that.
So my question is how can I properly marshal a two dimensional array of booleans, to that I can convert the class into an array of bytes to write to a binary file. Any help would be appreciated.
Thanks!
Kevin Yu [MSFT] - 11 Jun 2005 03:39 GMT Hi,
We have reviewed this issue and are currently researching on it. We will update you ASAP. Thanks for your patience!
Kevin Yu
 Signature ======= "This posting is provided "AS IS" with no warranties, and confers no rights."
"Peter Huang" [MSFT] - 13 Jun 2005 04:28 GMT Hi
We can not marshal a structure with a two dimensions array inside, we need to treat it as a single dimension array. Here is a link for your reference. http://groups-beta.google.com/group/microsoft.public.dotnet.framework.intero p/browse_thread/thread/68033197c75729be/912194d8cf731236?q=MVP+Marshal+two+d imensions+group:microsoft.public.dotnet.framework.interop&rnum=1&hl=en#91219 4d8cf731236
If you still have any concern, can you post your vb6 structure and the code your use to serialize to the disk, a simple vb6 project will be preferred.
Best regards,
Peter Huang Microsoft Online Partner Support
 Signature Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights.
Yan-Hong Huang[MSFT] - 15 Jun 2005 10:16 GMT Hello,
I am reviewing this issue thread. Do you have any more concerns on Peter's reply? If there is any unclear, please feel free to reply here and we will follow up.
Thanks very much for participating the community.
Best regards, Yanhong Huang Microsoft Community Support
Get Secure! ¨C www.microsoft.com/security Register to Access MSDN Managed Newsgroups! -http://support.microsoft.com/default.aspx?scid=/servicedesks/msdn/nospam.as p&SD=msdn
This posting is provided "AS IS" with no warranties, and confers no rights.
rmacias - 15 Jun 2005 17:01 GMT Thanks for all your replies.
I have tried to marshal it as a 1-Dim array. It writes it to disk as a one-dim array, but when the VB6 "Loader" app reads the binary file, I reads in the entire structure at the same time. All fields in the structure get populated correctly, except for the (now) 1-Dim array. I suspect that it is expecting it be a 2-Dim array.
Since Marshaling a 2-dim array is not possible, I need a way to simulate marshaling a 2-dim array. Using a Binary Editor, when VB6 writes a structure that has a two dim array to a binary file, there appears to be some sort of "header" (an extra 18 bytes) in front of the start of the array data. I suspect that these extra bytes define how the 2-Dim array is structured.
Can you verify how VB6 writes a structure containing a 2-dim array? What are these extra bytes? If I can simulate this somehow, this will probably get me going.
Thanks!
> Hello, > [quoted text clipped - 14 lines] > > This posting is provided "AS IS" with no warranties, and confers no rights. "Peter Huang" [MSFT] - 16 Jun 2005 08:22 GMT Hi
Here is my code to serialize the struture in vb6. Private Type Record ID As Long TwoDimArrayOfBool(2, 2) As Boolean End Type
Private Sub Command1_Click() Dim MyRecord As Record MyRecord.ID = 17 Dim i As Integer Dim j As Integer For i = 0 To 1 For j = 0 To 2 MyRecord.TwoDimArrayOfBool(i, j) = True Next Next For j = 0 To 2 MyRecord.TwoDimArrayOfBool(2, j) = False Next Open "c:\TESTFILE.dat" For Random As #1 Len = Len(MyRecord) Put #1, , MyRecord ' Write record to file. Close #1 ' Close file. End Sub
Because in vb6, Boolean variables are stored as 16-bit (2-byte) numbers.
The output is as below. 11 00 00 00 FF FF FF FF 00 00 FF FF FF FF 00 00 FF FF FF FF 00 00
11 00 00 00 'Long 4bytes
FF FF FF FF 00 00 FF FF FF FF 00 00 FF FF FF FF 00 00 ' 3X3X2 ,because a boolean is stored as 2 bytes in vb6.
So there is no header in the dump file.
Did I missing something?
Best regards,
Peter Huang Microsoft Online Partner Support
 Signature Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights.
rmacias - 17 Jun 2005 02:50 GMT Peter, thank you for your responses. I did forget to mention something. You are correct with the code you posted. However, what I forgot to mention (my apologies) is that the two Dim array of booleans are created dynamically, and not statically. Here is how to simulate what I have:
Public Type Dynamic2DimArray
TwoDimArrayOfBool() As Boolean
End Type
Private Sub Command1_Click()
Dim dynamicRecord As Dynamic2DimArray Dim i As Integer Dim j As Integer
ReDim dynamicRecord.TwoDimArrayOfBool(2, 2) For i = 0 To 1 For j = 0 To 2 dynamicRecord.TwoDimArrayOfBool(i, j) = True Next Next For j = 0 To 2 dynamicRecord.TwoDimArrayOfBool(2, j) = False Next
Open "C:\DynamicArray.dat" For Random As #2 Put #2, , dynamicRecord Close #2
End Sub
In a hex editor, the result is as follows:
02 00 03 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 ff ff ff ff 00 00 ff ff ff ff 00 00 ff ff ff ff 00 00
The last 18 bytes is the two dim array (same results you got from your test). However, there is an extra 18 bytes before the data. I suspect that this is some sort of "header" that describes the dimensions of the two dim array. I need to know what the format of this "header" is (if it is even a header). If I can simulate writing these extra 18 bytes, my c# program will be able to write in the exact format as the old application does.
Thanks your efforts. I really appreciate it!
> Hi > [quoted text clipped - 43 lines] > Get Secure! - www.microsoft.com/security > This posting is provided "AS IS" with no warranties, and confers no rights. "Peter Huang" [MSFT] - 17 Jun 2005 09:16 GMT Hi
Thanks for your quickly reply! Based on my research, the internal array structure of vb6 is not public. So far as a workaround I think we may call the vb code in c# to workaround the problem.
Add reference to Assembly microsoft.visualbasic c:\windows\microsoft.net\framework\v1.1.4322\microsoft.visualbasic.dll
using Microsoft.VisualBasic;
public struct Dynamic2DimArray { public Boolean[,] TwoDimArrayOfBool; //definition }
private void button1_Click(object sender, System.EventArgs e) { Dynamic2DimArray dda = new Dynamic2DimArray(); dda.TwoDimArrayOfBool =new Boolean[2,2]; for(int i=0;i<2;i++) for(int j=0;j<2;j++) dda.TwoDimArrayOfBool[i,j]=true; FileSystem.FileOpen(1, @"C:\DynamicArray4.dat", OpenMode.Random,OpenAccess.Default,OpenShare.Default,-1); FileSystem.FilePut(1, dda,-1); FileSystem.FileClose(1); }
Best regards,
Peter Huang Microsoft Online Partner Support
 Signature Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|