C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: PtrToStructureでfixedがコピー不可


(過去ログ 100 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■59861 / inTopicNo.1)  PtrToStructureでfixedがコピー不可
  
□投稿者/ asuka (41回)-(2011/06/09(Thu) 13:54:25)

分類:[C#] 

お世話になっております。

旧システム(VC++)から新システム(C#)へのデータ移行を行っております。

旧システムで定義した構造体データをファイルに書き込んでいます。
(バイナリデータ)

新システム側で旧システムで定義した構造体と同じものを定義し、

コピーしてC#側でデータを操作する作業を行っています。

unsafe fixedデータにおいては、最初のデータしか取得できない模様です。
http://objectmix.com/csharp/713479-marshal-not-copying-all-data-fixed-byte-array.html

何か良い手段があれば教えて頂きたく存じます。
m(__)m
---

構造体は下記の通りです。
// 14バイトの構造体
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TEST_STRUCT
{
 Public int a; // 4バイト
 Public int b; // 4バイト
 Public unsafe fixed short s[3]; // 6バイト
}

C#側で旧システムが作成したファイル情報を取得(FileInfoクラス)して、

C#側で定義した上記構造体へ入れる作業は以下の通りです。

using (Stream s = new FileStream(filePath, FileMode.Open))
{
 byte[] buf = new byte[Marshal.SizeOf(typeof(TEST_STRUCT))];
 s.Read(buf, 0, buf.Length);
 IntPtr ptr = Marshal.AllocHGlobal(buf.Length);

 try
 {
  Marshal.Copy(buf, 0, ptr, buf.Length);
  TEST_STRUCT test_struct = (TEST_STRUCT)Marshal.PtrToStructure(ptr, typeof(TEST_STRUCT));
・・・


Marshal.PtrToStructureが終わった後にtest_struct構造体のメンバを見てみますと、

a、bにはファイルの保存されたデータが取得されています。

sについては、s[0]のみ正しい値が取得出来ています。

色々と模索した結果、s[3]を

short s1; short s2; short s3とバラせば値を取れることが分かりました。

バラせばやりたいことは叶うのですが、実際の配列は3桁だったりするので、

バラす作業が大変なのと、スマートではないと思います。

public unsafe fixed short s[3];のままでデータを取得する方法はないでしょうか?

よろしくお願いします。
引用返信 編集キー/
■59865 / inTopicNo.2)  Re[1]: PtrToStructureでfixedがコピー不可
□投稿者/ Hongliang (784回)-(2011/06/09(Thu) 14:30:41)
// うち(Win7 x86/.NET 4/.NET 3.5 SP1)じゃ問題ないなぁ……。
Marshal.SizeOf(typeof(TEST_STRUCT))は期待通りの値になっていますか?
fixed ではなく、MarshalAs で UnmanagedType.ByValArray および SizeConst を使えばどうです?
引用返信 編集キー/
■59866 / inTopicNo.3)  Re[2]: PtrToStructureでfixedがコピー不可
□投稿者/ asuka (42回)-(2011/06/09(Thu) 14:51:57)
2011/06/09(Thu) 14:53:02 編集(投稿者)
2011/06/09(Thu) 14:52:54 編集(投稿者)

Hongliang さん。

レスありがとうございます。

> Marshal.SizeOf(typeof(TEST_STRUCT))は期待通りの値になっていますか?
期待通りの値になっています。
構造体サイズ14が返ってきます。

※実際ファイルに登録されるデータはこの構造体が複数登録されます。
よって、ファイルサイズをMarshal.SizeOf(typeof(TEST_STRUCT))で割って
割り切れるかどうかのチェックはしております。

> fixed ではなく、MarshalAs で UnmanagedType.ByValArray および SizeConst を使えばどうです?
例えば、文字型の場合ですとおっしゃる通り
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String moji; //32バイト
でいけます。

また、独自の構造体ですと、
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60)]
public Struct_Dokuji[] dokuji;

で定義可能で、読み込みもOKです。


ただし、アドバイス頂いた常用変数(int,shortなど)に上記定義をしますと、

コンパイルは通りますが、Marshal.SizeOf(typeof(TEST_STRUCT))を使用すると

例外が発生します。
アンマネージ構造体としてマーシャリングできません。
有効なサイズ、またはオフセットの計算ができません。

当初そのようにしておりましたが、例外が発生するので
unsafe fixedで定義しなおしました。

---
VS2010 C# .NetFramework4.0 Win7 x64

引用返信 編集キー/
■59867 / inTopicNo.4)  Re[1]: PtrToStructureでfixedがコピー不可
□投稿者/ 魔界の仮面弁士 (2208回)-(2011/06/09(Thu) 14:52:43)
No59861 (asuka さん) に返信
> unsafe fixedデータにおいては、最初のデータしか取得できない模様です。
当方では、下記のコードで取り出せています。

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TEST_STRUCT
{
    public int a;
    public int b;
    public unsafe fixed short s[3];
}

public class Program
{
    public static unsafe void Main()
    {
        string filePath = @"C:\data.dat";

        using (BinaryWriter wrt = new BinaryWriter(new FileStream(filePath, FileMode.Create)))
        {
            unchecked
            {
                wrt.Write((int)0x11223344); // int a;
                wrt.Write((int)0xaabbccdd); // int b;
                wrt.Write((short)0xfedc);   // short s[0];
                wrt.Write((short)0xba98);   // short s[1];
                wrt.Write((short)0x7654);   // short s[2];
            }
            wrt.Close();
        }

        // ファイルの中身:
        //   44 33 22 11 DD CC BB AA  DC FE 98 BA 54 76
        byte[] bin = File.ReadAllBytes(filePath);
        Console.WriteLine("file = {0}", BitConverter.ToString(bin));


        TEST_STRUCT test_struct;

        using (Stream s = new FileStream(filePath, FileMode.Open))
        {
            byte[] buf = new byte[Marshal.SizeOf(typeof(TEST_STRUCT))];
            s.Read(buf, 0, buf.Length);
            IntPtr ptr = Marshal.AllocHGlobal(buf.Length);
            Marshal.Copy(buf, 0, ptr, buf.Length);
            s.Close();
            test_struct = (TEST_STRUCT)Marshal.PtrToStructure(ptr, typeof(TEST_STRUCT));
            Marshal.FreeHGlobal(ptr);
        }

        Console.WriteLine("  a  = 0x{0:x8}", test_struct.a);
        Console.WriteLine("  b  = 0x{0:x8}", test_struct.b);
        Console.WriteLine("s[0] = 0x{0:x4}", test_struct.s[0]);
        Console.WriteLine("s[1] = 0x{0:x4}", test_struct.s[1]);
        Console.WriteLine("s[2] = 0x{0:x4}", test_struct.s[2]);

        Console.ReadLine();
    }
}

引用返信 編集キー/
■59868 / inTopicNo.5)  Re[3]: PtrToStructureでfixedがコピー不可
□投稿者/ 魔界の仮面弁士 (2209回)-(2011/06/09(Thu) 15:01:37)
No59866 (asuka さん) に返信
>>fixed ではなく、MarshalAs で UnmanagedType.ByValArray および SizeConst を使えばどうです?
> 当初そのようにしておりましたが、例外が発生するので
> unsafe fixedで定義しなおしました。

unsafe fixed 無しだとこんな感じ。


using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TEST_STRUCT
{
    public int a;
    public int b;
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I2, SizeConst = 3)]
    public short[] s;
}

public class Program
{
    public static void Main()
    {
        string filePath = @"C:\data.dat";

        using (BinaryWriter wrt = new BinaryWriter(new FileStream(filePath, FileMode.Create)))
        {
            unchecked
            {
                wrt.Write((int)0x11223344); // int a;
                wrt.Write((int)0xaabbccdd); // int b;
                wrt.Write((short)0xfedc);   // short s[0];
                wrt.Write((short)0xba98);   // short s[1];
                wrt.Write((short)0x7654);   // short s[2];
            }
            wrt.Close();
        }

        // ファイルの中身:
        //   44 33 22 11 DD CC BB AA  DC FE 98 BA 54 76
        byte[] bin = File.ReadAllBytes(filePath);
        Console.WriteLine("file = {0}", BitConverter.ToString(bin));


        TEST_STRUCT test_struct;
        using (Stream s = new FileStream(filePath, FileMode.Open))
        {
            byte[] buf = new byte[Marshal.SizeOf(typeof(TEST_STRUCT))];
            s.Read(buf, 0, buf.Length);
            IntPtr ptr = Marshal.AllocHGlobal(buf.Length);
            Marshal.Copy(buf, 0, ptr, buf.Length);
            s.Close();
            test_struct = (TEST_STRUCT)Marshal.PtrToStructure(ptr, typeof(TEST_STRUCT));
            Marshal.FreeHGlobal(ptr);
        }

        Console.WriteLine("  a  = 0x{0:x8}", test_struct.a);
        Console.WriteLine("  b  = 0x{0:x8}", test_struct.b);
        Console.WriteLine("s[0] = 0x{0:x4}", test_struct.s[0]);
        Console.WriteLine("s[1] = 0x{0:x4}", test_struct.s[1]);
        Console.WriteLine("s[2] = 0x{0:x4}", test_struct.s[2]);

        Console.ReadLine();
    }
}

引用返信 編集キー/
■59870 / inTopicNo.6)  Re[4]: PtrToStructureでfixedがコピー不可
□投稿者/ asuka (43回)-(2011/06/09(Thu) 15:36:04)
魔界の仮面弁士 さん

(サイトも含め)いつもお世話になっております。
m(__)m

ソースの開示までして頂き恐縮です。


1番目のソースをこちらでも試してみましたところ、上手くいっておりました。

コンソールアプリと何か違うのか疑問ですが、確かにunsafe fixedで定義されたshortの配列が全て取得出来ていました。

2番目のソースも上手くいきました。

わたしの定義の仕方が間違っておりました。
UnmanagedTypeをByValArrayとしておりましたが、下記の通り宣言することで全ての値が取得出来ておりました。
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I2, SizeConst = 3)]
public short[] s;

正直申し上げますと原因は不明のままです。TT

同じ現象の方(外国人)もいただけに、どう対処するのか分かりませんでしたが、

2番目の通り定義するようにしました。

いつも的確なアドバイスありがとうございます。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -