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

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

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

Re[2]: intptrからbyte配列へのマーシャリング


(過去ログ 111 を表示中)

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

■65613 / inTopicNo.1)  intptrからbyte配列へのマーシャリング
  
□投稿者/ オイル (1回)-(2013/03/11(Mon) 18:05:56)

分類:[C#] 

2013/03/11(Mon) 18:08:08 編集(投稿者)
開発環境:VisualStudio2005 C#


現在、32bitOSから64bitOSへのシステム対応をしているのですが、下記コードで例外エラーになります。

該当行:「Marshal.Copy(bioApiData.Data, bitmapData, 0, (int)bioApiData.Length);」
エラー内容:「保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。」



	[StructLayout(LayoutKind.Explicit, Size = 8)]
	struct PvsApiIfBioAPIData
	{
		[FieldOffset(0)]public UInt32 Length;
		[FieldOffset(4)]public IntPtr Data;
	}

	[StructLayout(LayoutKind.Explicit, Size=12)]
	struct PvsApiIfBioAPIGuiBitmap
	{
		[FieldOffset(0)]public UInt32 Width;
		[FieldOffset(4)]public UInt32 Height;
 		[FieldOffset(8)]public IntPtr Bitmap;
	}

	/// <summary>
	/// Callback function for image notification.
	/// </summary>
	/// <param name="guiStreamingCallbackCtx">Context pointer</param>
	/// <param name="sampleBuffer">Silhouette image information</param>
	/// <returns>
	/// <see cref="PvsBioAPITypes.PVS_APIIF_BIOAPI_OK">Normal end</see>(Fixed)
	/// </returns>
	/// <remarks>
	/// Method that is called by Authentication library.<para/>
	/// If callback function is set by application, notify the silhouette to application.<para/>
	/// </remarks>
	private UInt32 BioApiStreamingCallback(IntPtr guiStreamingCallbackCtx, IntPtr sampleBuffer)
	{
		if (!sampleBuffer.Equals(IntPtr.Zero)) {

			PvsApiIfBioAPIGuiBitmap bioApiGuiBitmap = new PvsApiIfBioAPIGuiBitmap();
			bioApiGuiBitmap = (PvsApiIfBioAPIGuiBitmap)Marshal.PtrToStructure(sampleBuffer, typeof(PvsApiIfBioAPIGuiBitmap));
       
        			PvsApiIfBioAPIData bioApiData = new PvsApiIfBioAPIData();
        			bioApiData = (PvsApiIfBioAPIData)Marshal.PtrToStructure(bioApiGuiBitmap.Bitmap, typeof(PvsApiIfBioAPIData));
        
			if ((0 != bioApiData.Length) && (!bioApiData.Data.Equals(IntPtr.Zero))) {
                 		byte[] bitmapData = new byte[bioApiData.Length];
                		Marshal.Copy(bioApiData.Data, bitmapData, 0, (int)bioApiData.Length);

                		PvsSilhouetteInfo info = new PvsSilhouetteInfo();
                		info.Width = bioApiGuiBitmap.Width;
                		info.Height = bioApiGuiBitmap.Height;
                		info.Data = new MemoryStream(bitmapData);

                		// Notify to application.
                		if (null != callbackToGui)
                		{
                		    callbackToGui(PvsApiIfTypes.PVS_APIIF_SAMPLE_AVAILABLE, 0, info);
                		}

                		info.Dispose();
			}
		}
		return PvsBioAPITypes.PVS_APIIF_BIOAPI_OK;
	}



データの値は下のように入っています。
-----------64bitOS-----------
sampleBuffer 604031672
bioApiGuimap 
 width  640
 height 480
 bitmap 604031688
bioApiData 
 Data   2366844532814511099
 Length 308278

-----------32bitOS-----------
sampleBuffer 112183332
bioApiGuimap 
 width  640
 height 480
 bitmap 112183344
bioApiData 
 Data   79888456
 Length 308278



sampleBufferをbioApiGuimapにマーシャリングしているところで
64bitのbitmapはアドレスの値が16増えているのに対し、
32bitのbitmapはアドレスの値が12しか増えていないあたり
intPtrの扱いが64bitと32bitで違うのかもしれませんが
エラーの原因と具体的にどうすればよいのか分かりません。どうかご教授願います。

今までVBの経験しかなかったものでコードや内容で
足りない部分がございましたらご指摘お願いいたします。

引用返信 編集キー/
■65615 / inTopicNo.2)  Re[1]: intptrからbyte配列へのマーシャリング
□投稿者/ Hongliang (38回)-(2013/03/11(Mon) 18:21:46)
64bitプロセスにしないといけませんか?
プラットフォームターゲットをx86にすれば32bitプロセスとして今までと変わらなく動作すると思いますが。

> [StructLayout(LayoutKind.Explicit, Size = 8)]
> struct PvsApiIfBioAPIData
> {
>	[FieldOffset(0)]public UInt32 Length;
>	[FieldOffset(4)]public IntPtr Data;
> }
64bitプロセスだとポインタ類は当然64bitになりますから、32bit+64bitがSize=8に収まるはずがありません。
// PvsApiIfBioAPIData構造体のサイズとDataメンバの位置は、DLLでアラインメントがどう定義されているかも影響します。

引用返信 編集キー/
■65616 / inTopicNo.3)  Re[1]: intptrからbyte配列へのマーシャリング
□投稿者/ 魔界の仮面弁士 (168回)-(2013/03/11(Mon) 18:46:38)
2013/03/11(Mon) 18:52:27 編集(投稿者)

No65610 (oil さん) に返信
No65613 (オイル さん) に返信
> 手のひらから読み込んだ静脈データを画面に表示する処理を行っているのですが

指先ではなく掌ということは、富士通系の静脈認証開発でしょうか。
それとも生体認証系では無く、医療画像処理系の開発かな…。


> intPtrの扱いが64bitと32bitで違うのかもしれませんが
一応補足しておくと、intPtr ではなく IntPtr です。
C# は、(VB とは違って)大文字小文字が区別される言語なので。


その IntPtr 型というものは、WOW64 で動作させるなら 32bit 幅となります。
x86 ビルドでは常に 32bit幅となり、
x64 ビルドでは、常に64bit幅となるデータ型ですので。

AnyCPU ビルドの場合は、実行環境に応じて 32bit か 64bit かが異なりますが、
現在どちらのモードになっているかを IntPtr.Size プロパティで判定できます。

そして今回は、VS2005 ということなので、特に指定しなければ
AnyCPU ビルドが既定値になっているはずです。この場合、実行環境によって
構造体サイズが変わりますから、Explicit にするなら、x86用とx64用とで、
2つの構造体定義を用意しなければならず、手間がかかります。

特に Explicit に思い入れが無ければ、FieldOffset を使わずに
[StructLayout(LayoutKind.Sequential, Pack = パッキング幅)]
の属性指定とした方が良いかも知れません。

オフセット指定の方が好みであれば、構造体に変換しようとはせず、
ポインタのまま Marshal.ReadIntPtr メソッド等で読み取る手もあります。
可読性は犠牲になりそうですけれどね。


> PvsApiIfBioAPIGuiBitmap bioApiGuiBitmap = new PvsApiIfBioAPIGuiBitmap();
> bioApiGuiBitmap = (PvsApiIfBioAPIGuiBitmap)Marshal.PtrToStructure(sampleBuffer, typeof(PvsApiIfBioAPIGuiBitmap));

その後で別の値を代入する予定なのに、何故、事前に new しているのしょうか?


> どうかご教授願います。
http://www.tt.rim.or.jp/~rudyard/torii009.html
引用返信 編集キー/
■65970 / inTopicNo.4)  Re[2]: intptrからbyte配列へのマーシャリング
□投稿者/ オイル (2回)-(2013/03/27(Wed) 17:10:28)
No65615 (Hongliang さん) に返信

すぐ返事をいただいたのに返信が遅くなってしまいすみません。


> 64bitプロセスにしないといけませんか?
> プラットフォームターゲットをx86にすれば32bitプロセスとして今までと変わらなく動作すると思いますが。
このシステムから呼び出しているDLLがx64として作成されているようで
プラットフォームターゲットをx86にしてしまうとエラーになってしまいました。

>>[StructLayout(LayoutKind.Explicit, Size = 8)]
>>struct PvsApiIfBioAPIData
>>{
> > [FieldOffset(0)]public UInt32 Length;
> > [FieldOffset(4)]public IntPtr Data;
>>}
> 64bitプロセスだとポインタ類は当然64bitになりますから、32bit+64bitがSize=8に収まるはずがありません。
> // PvsApiIfBioAPIData構造体のサイズとDataメンバの位置は、DLLでアラインメントがどう定義されているかも影響します。

typedef struct bioapi_data
{
uint32 Length; /* in bytes */
uint8 *Data;
} BioAPI_DATA, *BioAPI_DATA_PTR;
ヘッダーファイルには上記のように記載されていたのですが、
この場合は32bit+8bitでsizeが4+1=5だけど
32bitの場合はUInt32が32bit、IntPtrが32bitなのでsizeが4+4=8になっていたということでしょうか?

試しにSizeを12に変更してみましたが結果は変わらずでした。
引用返信 編集キー/
■65975 / inTopicNo.5)  Re[2]: intptrからbyte配列へのマーシャリング
□投稿者/ オイル (3回)-(2013/03/27(Wed) 17:54:28)
No65616 (魔界の仮面弁士 さん) に返信
> 2013/03/11(Mon) 18:52:27 編集(投稿者)

返事が遅れてしまい、申し訳ありません。

> 指先ではなく掌ということは、富士通系の静脈認証開発でしょうか。
> それとも生体認証系では無く、医療画像処理系の開発かな…。
前者です。静脈認証を用いた出退勤管理システムの開発です。


>>intPtrの扱いが64bitと32bitで違うのかもしれませんが
> 一応補足しておくと、intPtr ではなく IntPtr です。
> C# は、(VB とは違って)大文字小文字が区別される言語なので。

> そして今回は、VS2005 ということなので、特に指定しなければ
> AnyCPU ビルドが既定値になっているはずです。この場合、実行環境によって
> 構造体サイズが変わりますから、Explicit にするなら、x86用とx64用とで、
> 2つの構造体定義を用意しなければならず、手間がかかります。
最初はx64用とx86用で共通のものにしようと考えていたのですが、
提供されているDLLがx86とx64で別々に提供されていたため
保守が面倒ですが別々に作成しています。

>
> 特に Explicit に思い入れが無ければ、FieldOffset を使わずに
> [StructLayout(LayoutKind.Sequential, Pack = パッキング幅)]
> の属性指定とした方が良いかも知れません。
[StructLayout(LayoutKind.Sequential, Pack = 8)]に変更することで表示ができました!
仕組みについてはまだ理解不足なところもあるのでこれから勉強していきます!


>>PvsApiIfBioAPIGuiBitmap bioApiGuiBitmap = new PvsApiIfBioAPIGuiBitmap();
>>bioApiGuiBitmap = (PvsApiIfBioAPIGuiBitmap)Marshal.PtrToStructure(sampleBuffer, typeof(PvsApiIfBioAPIGuiBitmap));
> その後で別の値を代入する予定なのに、何故、事前に new しているのしょうか?
前任者がコーディングをして見過ごしていたのですが、確かにnewする必要はありませんね。
こちらも合わせて修正させてもらいました。


>>どうかご教授願います。
> http://www.tt.rim.or.jp/~rudyard/torii009.html
普段から使っていてあまり意識したことがなかったのですが、
今回の私の質問だと正しくは「ご教示願います」ですね。

いろいろと勉強になりました。どうも、ありがとうございます!

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


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

このトピックに書きこむ

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

管理者用

- Child Tree -