トップ回答者
APIのReadFile関数を使ってデータを読み込む方法

質問
-
こんにちは、C#でAPIのReadFile関数を使ったデータの読み込み方法について質問させていただきます。
MSDNプログラミングガイド等を参考にしてReadFile関数を使ったプログラムを以下のように記述しました(一部抜粋)。
デバッグ中にReadFile関数の第四引数を見ると、たしかにデータが受信されていることがわかったのですが、
第二引数に肝心のデータが格納されていませんでした。
[System.Runtime.InteropServices.DllImport("kernel32", SetLastError = true)]
static extern unsafe bool ReadFile
(
System.IntPtr hFile, // handle to file
void* pBuffer, // data buffer
int NumberOfBytesToRead, // number of bytes to read
int* pNumberOfBytesRead, // number of bytes read
int Overlapped // overlapped buffer
);
int n = 0;
byte[] buffer = new byte[128];
fixed (byte* p = buffer)
{
ReadFile(readhandle, p, lpNumberOfBytesRead, &n, 0);
}
以上がソースの主要部分を抜粋したものです。
ビルドエラー等は出ない状態ですが、第二引数に肝心のデータが格納されず困っています。
よろしければご回答ください。
[参考]MSDNプログラミングガイド: http://msdn.microsoft.com/ja-jp/library/2d9wy99d(VS.80).aspx
回答
-
ハンドルは SafeHandle(SafeFileHandle)に、overlapped は(NULL 渡すの前提なら) IntPtr にすべき、と少し気になるところはありますが問題ない宣言及び使用方法ですね。
ReadFile の返値はどうなっていますか?
pNumberOfBytesRead に返ってきてる値は NumberOfBytesToRead に渡したのと同じ(か読み取り先の EOF までの長さ)になっていますか?
hFile に何を渡しているのか知りませんが、FileStream で開いたファイルの Handle プロパティを使った場合はどうですか?- 回答としてマーク sk7474 2009年4月1日 7:27
-
3052F の発言:
・hFileにはUSB通信のためのPipeハンドラを渡しています。
で、
Hongliang の発言:hFile に何を渡しているのか知りませんが、FileStream で開いたファイルの Handle プロパティを使った場合はどうですか?
はどうなんですか?
また、FileStream コンストラクタには IntPtr(または SafeFileHandle)を渡すこともできます(デフォルトでは FileStream を Close すれば自動的に CloseHandle Win32API 関数によって渡したハンドルがクローズされますが、引数次第でそうさせないこともできます)。こちらではどうでしょうか?3052F の発言:
>!(^^)!ふ~さん
以下のコードでエラー取得しました。[DllImport("kernel32.dll", SetLastError=true)] // SetLastErrorフィールドにtrueを設定しMarshal.GetLastWin32Errorメソッドを有効化
if (lpNumberOfBytesRead != 0) // 受信データが存在する場合
{
int er = 0; // Win32エラーコード取得用変数
er = Marshal.GetLastWin32Error(); // Win32エラーコード取得
}GetLastError が有効なのは(同期 Read の場合)ReadFile が false を返したときのみです。
lpNumberOfBytesRead は既に EOF に到達していた場合でも 0 を返すので、関数呼び出しの成否の判定に使ってはいけません。- 回答としてマーク sk7474 2009年4月1日 7:26
-
明後日な方向な回答として…
FileStreamコンストラクタを使用してFileStreamクラスでラップしてしまうのはどうでしょう?
そうすれば他のFileStreamとして簡単に扱えるようになります。
もちろんちゃんと扱えるようになったらSafeFileHandle版に切り替えましょう。- 回答としてマーク sk7474 2009年4月1日 7:26
すべての返信
-
ハンドルは SafeHandle(SafeFileHandle)に、overlapped は(NULL 渡すの前提なら) IntPtr にすべき、と少し気になるところはありますが問題ない宣言及び使用方法ですね。
ReadFile の返値はどうなっていますか?
pNumberOfBytesRead に返ってきてる値は NumberOfBytesToRead に渡したのと同じ(か読み取り先の EOF までの長さ)になっていますか?
hFile に何を渡しているのか知りませんが、FileStream で開いたファイルの Handle プロパティを使った場合はどうですか?- 回答としてマーク sk7474 2009年4月1日 7:27
-
お返事ありがとうございます。C#を始めたばかりだったのでお返事いただけて助かります。
>Hongliangさん
・実はハンドルはUSB通信のために取得しており、SafeHandleも検討していたのですが
ここがReadFile関数の第二引数に受信したデータが格納されない重要な原因ではないと判断し見送っていました。
・第五引数overlappedはIntPtrにさせていただきました。
・ReadFileの戻り値ですが受信がないときはfalse, 受信があったときはtrueで見ています。
・ターゲットから送信したデータと、ホストで受け取ったデータ長は同じ長さであることをReadFile関数の第四引数の中身で確認しています。
・hFileにはUSB通信のためのPipeハンドラを渡しています。そのほかに第二引数にデータが格納されない(バッファの設定がよくない)原因がありますでしょうか?よろしくお願いします。
>!(^^)!ふ~さん
以下のコードでエラー取得しました。[DllImport("kernel32.dll", SetLastError=true)] // SetLastErrorフィールドにtrueを設定しMarshal.GetLastWin32Errorメソッドを有効化
if (lpNumberOfBytesRead != 0) // 受信データが存在する場合
{
int er = 0; // Win32エラーコード取得用変数
er = Marshal.GetLastWin32Error(); // Win32エラーコード取得
}このコードを用いて取得されたエラーコードは1008でした(Dec)。
エラーコード1008は以下の通りでした。ERROR_NO_TOKEN 1008 0x000003F0 存在しないトークンを参照しようとしました。
このエラーはバッファの設定がよくないのでしょうか?よろしくお願いします。
-
3052F の発言:
・hFileにはUSB通信のためのPipeハンドラを渡しています。
で、
Hongliang の発言:hFile に何を渡しているのか知りませんが、FileStream で開いたファイルの Handle プロパティを使った場合はどうですか?
はどうなんですか?
また、FileStream コンストラクタには IntPtr(または SafeFileHandle)を渡すこともできます(デフォルトでは FileStream を Close すれば自動的に CloseHandle Win32API 関数によって渡したハンドルがクローズされますが、引数次第でそうさせないこともできます)。こちらではどうでしょうか?3052F の発言:
>!(^^)!ふ~さん
以下のコードでエラー取得しました。[DllImport("kernel32.dll", SetLastError=true)] // SetLastErrorフィールドにtrueを設定しMarshal.GetLastWin32Errorメソッドを有効化
if (lpNumberOfBytesRead != 0) // 受信データが存在する場合
{
int er = 0; // Win32エラーコード取得用変数
er = Marshal.GetLastWin32Error(); // Win32エラーコード取得
}GetLastError が有効なのは(同期 Read の場合)ReadFile が false を返したときのみです。
lpNumberOfBytesRead は既に EOF に到達していた場合でも 0 を返すので、関数呼び出しの成否の判定に使ってはいけません。- 回答としてマーク sk7474 2009年4月1日 7:26
-
こんにちは!(^^)!ふ~です。
仮に、確かなエラーメッセージとしますと、下記のような関連でしょうか?
すべてのユーザーへのアクセスを匿名パイプを作成する方法
http://support.microsoft.com/kb/813414/ja -
明後日な方向な回答として…
FileStreamコンストラクタを使用してFileStreamクラスでラップしてしまうのはどうでしょう?
そうすれば他のFileStreamとして簡単に扱えるようになります。
もちろんちゃんと扱えるようになったらSafeFileHandle版に切り替えましょう。- 回答としてマーク sk7474 2009年4月1日 7:26