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

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

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

Re[4]: ushort配列のポインタ


(過去ログ 65 を表示中)

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

■37704 / inTopicNo.1)  ushort配列のポインタ
  
□投稿者/ ぬーぼー (2回)-(2009/06/29(Mon) 11:29:06)

分類:[.NET 全般] 

2009/06/29(Mon) 11:29:54 編集(投稿者)
2009/06/29(Mon) 11:29:46 編集(投稿者)

ぬーぼーと申します。

C#にてプリンタのジョブを管理するためのプログラムに、WinAPIを使うことにしたのですが、その際に使用する構造体「PRINTER_NOTIFY_OPTIONS_TYPE」へ値を設定するところで躓いています。


C++では、
typedef struct _PRINTER_NOTIFY_OPTIONS_TYPE {
WORD Type;
WORD Reserved0;
DWORD Reserved1;
DWORD Reserved2;
DWORD Count;
PWORD pFields;
}
と定義されているので、それをC#に置き換えると、
public class PRINTER_NOTIFY_OPTIONS_TYPE
{
public ushort wType;
public ushort wReserved0;
public uint dwReserved1;
public uint dwReserved2;
public uint FieldCount;
public IntPtr pFields;

}
となると思います。
その中のpFieldsにushortの配列
ushort[] JobFields = {0x01,0x02,0x03,0x04,0x05,0x06};

を設定したいと思っているのですが、この配列のポインタを取得しようと、

PRINTER_NOTIFY_OPTIONS_TYPE hoge = new PRINTER_NOTIFY_OPTIONS_TYPE();
Marshal.StructureToPtr(JobFields, hoge.pFields, true);

としたところ、「指定された構造体は高速転送型か、またはレイアウト情報を含んでいなければなりません。」
となってしまいます。
別の方法として、

PRINTER_NOTIFY_OPTIONS_TYPE hoge = new PRINTER_NOTIFY_OPTIONS_TYPE();
hoge.pFields = Marshal.AllocHGlobal(Marshal.SizeOf(JobFields[0]) * JobFields.Length);
int ofs = 0;
for (int i = 0; i < JobFields.Length; i++)
{
Marshal.WriteInt16(Notifications1.pFields, ofs, (short)JobFields[i]);
ofs += Marshal.SizeOf(JobFields[i]);
}
ともしてみたのですが、正しいのかどうか...

どうか、「こうすれば」というのがあれば、お教えください。
よろしくお願いいたします。

引用返信 編集キー/
■37723 / inTopicNo.2)  Re[1]: ushort配列のポインタ
□投稿者/ Hongliang (429回)-(2009/06/29(Mon) 14:36:07)
マーシャリングにおいて、アンマネージポインタを配列として C# の構造体メンバに含めることはできません。
IntPtr で定義して Marshal クラスのメソッドで操作するなり、そのまま C# でもポインタとして扱うなりしてください。
引用返信 編集キー/
■37848 / inTopicNo.3)  Re[2]: ushort配列のポインタ
□投稿者/ ぬーぼー (3回)-(2009/07/01(Wed) 22:25:03)
2009/07/01(Wed) 22:25:53 編集(投稿者)

Hongliang さん
遅くなりましたが、お返事ありがとうございます。
頂いた回答から、以下の方法で実現できました。

unsafe public class PRINTER_NOTIFY_OPTIONS_TYPE
{
 public ushort wType;
 public ushort wReserved0;
 public uint dwReserved1;
 public uint dwReserved2;
 public uint FieldCount;
 public ushort* pFields;

}
ushort[] JobFields = {0x01,0x02,0x03,0x04,0x05,0x06};

関数 {
 PRINTER_NOTIFY_OPTIONS_TYPE hoge = new PRINTER_NOTIFY_OPTIONS_TYPE();
  unsafe{
   fixed (ushort* p = JobFields) hoge.pFields = p;
  }
}

ただ、調べた限りでの自分の解釈では、JobFields配列はマネージドなので、必要な時に改めて
unsafe{
fixed (ushort* p = JobFields) hoge.pFields = p;
}
をし直すのと、処理が終わるまではJobFields配列をロック(?)する必要があるのかなと思ってます。
(今は、意図通りに動いてますが)
引用返信 編集キー/
■37849 / inTopicNo.4)  Re[3]: ushort配列のポインタ
□投稿者/ Hongliang (432回)-(2009/07/01(Wed) 22:48:36)
一応念のため。
>   unsafe{
>    fixed (ushort* p = JobFields) hoge.pFields = p;
>   }
fixed で得たポインタを fixed の外に持ち出してはいけません。
hoge を使っている間はずっと fixed し続けてください。
引用返信 編集キー/
■37872 / inTopicNo.5)  Re[4]: ushort配列のポインタ
□投稿者/ ぬーぼー (4回)-(2009/07/02(Thu) 12:15:10)
Hongliang さん

まさにそのミスをしていました!

ポインタが必要だったのも1つではなかったので、MSのドキュメント通り、
fixedを入れ子にして、処理が終わるまで、閉じないようにしました。

本当にありがとうございました。
解決済み
引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -