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

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

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

Re[2]: ExcelVBAに固定長byte配列を含む構造体の定義方法


(過去ログ 111 を表示中)

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

■65731 / inTopicNo.1)  ExcelVBAに固定長byte配列を含む構造体の定義方法
  
□投稿者/ doragora (6回)-(2013/03/15(Fri) 11:36:11)

分類:[Microsoft Office 全般] 

No65664の質問に続くのですが、一応動作するコードは出来たのですが、イマイチスッキリしない部分があるのでお知恵を拝借できれば。


☆やりたいこと
ExcelVBAのユーザ定義型で、byte配列のフィールドを持ちたい

☆問題
・一応動作はしています。がスッキリしない。
・COPYDATASTRUCTのlpDataに、さらにStringのポインタを入れても対処してくれないので固定長で苦肉の策

☆環境
・Win7 x64
・Excel 2007
・VS 2012

☆注意点
・unsafe初めて使いました。MarshalかC/C++でWrapper作成で今までは済んでいたので。

☆C#
...
// public const int STRUCT_STRING_MAXLENGTH = 1024;
    public unsafe struct ReserveStruct
    {
        public enumReserveCategory Category;
        public Int32 No;
        public fixed byte Name[common.STRUCT_STRING_MAXLENGTH];
        public fixed byte Comment[common.STRUCT_STRING_MAXLENGTH];
    }
...
            Encoding enc = Encoding.Unicode;

            ReserveStruct Reserve = default(ReserveStruct);
            Reserve.Category = Category;
            Reserve.No = No;
            unsafe
            {
                byte[] Name_buf = enc.GetBytes(Name);
                byte* pName = Reserve.Name;
                for (int i = 0; i < Name_buf.Length; i++)
                {
                    if (!(i < STRUCT_STRING_MAXLENGTH)) break;
                    *pName = Name_buf[i];
                    pName++;
                }

                byte[] Comment_buf = enc.GetBytes(Comment);
                byte* pComment = Reserve.Comment;
                for (int i = 0; i < Comment_buf.Length; i++)
                {
                    if (!(i < STRUCT_STRING_MAXLENGTH)) break;
                    *pComment = Comment_buf[i];
                    pComment++;
                }

            }

            COPYDATASTRUCT data = new COPYDATASTRUCT();
            data.dwData = new IntPtr(common.DW_RESERVE);
            data.cbData = (uint)Marshal.SizeOf(Reserve);
            data.lpData = Marshal.AllocHGlobal(Marshal.SizeOf(Reserve));
            Marshal.StructureToPtr(Reserve, data.lpData, false);
            try
            {
                IntPtr pData = Marshal.AllocHGlobal(Marshal.SizeOf(data));
                Marshal.StructureToPtr(data, pData, false);
                try
                {
                    common.SendMessage(hWnd, common.WM_COPYDATA, IntPtr.Zero, pData);
                }
                finally
                {
                    Marshal.FreeHGlobal(pData);
                }
            }
            finally
            {
                Marshal.FreeHGlobal(data.lpData);
            }
...

☆ExcelVBA
...
Public Const STRUCT_STRING_MAXLENGTH As Integer = (1024 / 2)    ' 1024バイトでもUnicodeだから512文字だから一応動くケド...
Public Type ReserveStructAPI
    Category As Long
    No As Long
    Name As String * STRUCT_STRING_MAXLENGTH                    ' Name(STRUCT_STRING_MAXLENGTH) As Byte みたいに出来ないか?
    Comment As String * STRUCT_STRING_MAXLENGTH                 ' 
End Type

Public Type ReserveStruct
    Category As enumReserveCategory
    No As Long
    Name As String
    Comment As String
End Type

...
Private Function ReserveProc(ByRef data As COPYDATASTRUCT) As ReserveStruct
    
    Dim Reserve As ReserveStructAPI
    CopyMemory VarPtr(Reserve), data.lpData, data.cbData
    
    ReserveProc.Category = Reserve.Category
    ReserveProc.No = Reserve.No
    ReserveProc.Name = Left$(Reserve.Name, InStr(Reserve.Name, Chr$(0)) - 1)
    ReserveProc.Comment = Left$(Reserve.Comment, InStr(Reserve.Comment, Chr$(0)) - 1)
    
End Function
...

☆
googleで検索しても、VBA VB6 VB(.NET)の情報が混在して探しにくいですね。
VBFixedArray属性付けたい。

引用返信 編集キー/
■65752 / inTopicNo.2)  Re[1]: ExcelVBAに固定長byte配列を含む構造体の定義方法
□投稿者/ 魔界の仮面弁士 (172回)-(2013/03/15(Fri) 20:44:32)
No65731 (doragora さん) に返信
> ExcelVBAのユーザ定義型で、byte配列のフィールドを持ちたい

バイナリで持たせるなら、
>     Comment As String * STRUCT_STRING_MAXLENGTH                 ' 
の部分を
 Comment(STRUCT_STRING_MAXLENGTH - 1) As Byte   '静的配列
あるいは
 Comment() As Byte   '動的配列
のような宣言にすることもできます。


> ' Name(STRUCT_STRING_MAXLENGTH) As Byte みたいに出来ないか?
Name ステートメントと被るので、別の名前にする必要があります。

ちなみに Name ステートメントは、ファイルの移動やリネームを行うための命令です。
例:『Name "C:\oldPath\File1.txt" As "C:\newPath\File1.txt"』

引用返信 編集キー/
■65754 / inTopicNo.3)  Re[2]: ExcelVBAに固定長byte配列を含む構造体の定義方法
□投稿者/ doragora (7回)-(2013/03/15(Fri) 23:04:23)
No65752 (魔界の仮面弁士 さん) に返信

>  Comment(STRUCT_STRING_MAXLENGTH - 1) As Byte   '静的配列

ご指摘通り行ったらうまくいきました。
☆C#
?Marshal.SizeOf(Reserve)
2056

☆Excel VBA
?lenb(Reserve)
 2056 

>>' Name(STRUCT_STRING_MAXLENGTH) As Byte みたいに出来ないか?
> Name ステートメントと被るので、別の名前にする必要があります。
> 
> ちなみに Name ステートメントは、ファイルの移動やリネームを行うための命令です。
> 例:『Name "C:\oldPath\File1.txt" As "C:\newPath\File1.txt"』

なるほど。
エラーが表示される時カーソルがByteの所に来ていたので、そっちばっかり気にしていました。
試しに
Public Type ReserveStructAPI
    Category As Long
    No As Long
    Comment(STRUCT_STRING_MAXLENGTH - 1) As Byte
    Name(STRUCT_STRING_MAXLENGTH - 1) As Byte     ' この行でエラーになる
End Type
CommentフィールドとNameフィールドの定義順を交換したら、自分でも気づいてたと思うのですが。
調査不足でした。Nameフィールド名を変更することで対処したいと思います。

ご指摘ありがとうございました。

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


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

このトピックに書きこむ

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

管理者用

- Child Tree -