C♯相談室 Part8

このエントリーをはてなブックマークに追加
935934:02/12/11 23:21
ちなみにエラーは別のプロセスがそのファイルを使用しています。とかいう趣旨のもの。
エラーを拾って構造的な処理をしたいのではなくて、ただそのエラーが出るのが分かっているので無視して処理を進めたいということです。
936デフォルトの名無しさん:02/12/11 23:23
現在、ListViewにデータを表示するアプリケーションを作成しています。
ListViewクラスはデータをListView内に保持するので、自作クラスにデータを持っていると
データの2重管理になってしまいます。
Model/Viewのような感じにしたいのですが、そういった考えは古いのでしょうか?
>>936
ListView以外にViewを持つ可能性があるなら、Model/Viewにして
データを二重持ちにしたほうがいいだろうねえ。

その可能性がないならListView派生クラスにボッコボッコ埋め込む。
>>935
try{}catch{}finally{}
catchしる。
939936:02/12/12 00:24
>>937
どうもです。
リストビューで使うデータは他の表示でも使うので、どうしようかと。。
2重にするとデータの入れ替えとか起きたときに整合性を保つのが大変っぽい。
やっぱリストビューを表示とデータ管理クラス両方の役にするのがいいっぽいかな。
>>939
他のViewがあるなら、迷わず二重持ちにするけどなあ・・・

その、他のViewが参照のみで、操作をしないのであれば、
ListViewがデータ管理役になっても大丈夫かな?
941934:02/12/12 00:33
>>938
特にしたい処理がなければfinallyだけで良いと思っていたんだけど。
空のcatchでやってみます。thanks
>>941
キャッチしないと例外が外に飛び出てっちゃうよ
943934:02/12/12 02:52
>>942
try-finally だけの構文もありと書いてあったので、一番一般化されたエラー処理はこれなのかなと思っていました。
それはなんのためにあるの?
>>943
漏れはそのtry-finallyは使わないけど
メソッド使用してる側でcatchすれば用が足りる時、使えるかもね
でも
try{}catch(Exception error){ throw error;}finally{}
ってしたほうがわかりやすいと漏れは思ってる。あくまで漏れの考えだけどね・・・
>>943
そいやbefore/Afterパターンってのにも使えるねtry-finallyは。
http://www.hyuki.com/dp/dpinfo.html#BeforeAfter
946デフォルトの名無しさん:02/12/12 04:45
>>939
迷わずModel/Viewにするのがいいんでは?
データは一元管理にしないといかんでしょ
そうしないと、いわれてるように更新、同期の管理など大変に.
ListViewだとどう実装するのかは知らないんですが、オーナードローになるのかな?
マスひとつひとつをセルとすると必要なセルの表示時にデータを見に行って表示って感じか
947名無しさん♯:02/12/12 07:48
948デフォルトの名無しさん:02/12/12 19:08
ほほう、C#でデリゲート以外のコールバックができるとな?
ここはC#のスレであって、C++のスレじゃないぞ。
ちなみに俺は解決した。
他にできる奴はいねーの?(藁
>>948
パターン名で言ったらなんだい?
>>948
俺できるよ。でもそんなひれくれた聞き方するやつになんか教えない(藁
>>950
嘘つくな。お前にできるわけねーだろ。
本当だと言い張るんならソース見せてみろ。
>>951
嫌。出来ないと思われても良いよ。見せるよりマシ。
>>952
はったりプ。
954デフォルトの名無しさん:02/12/12 23:43
>>948
ばかじゃねーの。いいかげんにしろ。
>>950
次スレ立てろヴォケ
>>955
わかりました。
957&diamonds;:02/12/13 00:56
>956
立ってるよ
958デフォルトの名無しさん:02/12/13 01:06
ほどよく荒れてるな(W
959950:02/12/13 01:09
>>957
俺が立てました。
960picty:02/12/13 03:25
C言語で一定周期(100ms以内)の信号を画面に表示させたいのですが、
どの関数を使ったらよいかわかりません。どなたか教えていただけませんか?
961デフォルトの名無しさん:02/12/13 04:18
>>960 いちおうこのスレはC#の質問なのでCの質問スレ捜して聞いてみたほうがいいよ。
それに質問も漠然としてるね。信号とはなんだろう。
C#、.Netで一定時間毎に何か処理させたいときはタイマーをフォームに貼り付けて、イベントハンドラを書くというのがやり方だけど。
unsafe コンテキストで
MyStruct s = new MyStruct( Hogehoge );
SomeNativeMethod( new IntPtr( &s ) );
// MyStruct preventOptimizing = s; // コメントはずすと正しく動くよ

ってな感じで、メソッドに渡すだけの構造体を使うと、
最適化で消滅して正しく動かなくなるんだよねぇ。
アドレス取ってるんだから最適化しても残さないといけないと思うんだけど。
だからpinしろって。
そういや、C#って、かなり積極的にガベコレしてるね。
965デフォルトの名無しさん:02/12/13 08:54
>>964 ソースは?どうしてそう思ったんだい?
デバッガでこまめにメモリ内容チェックしたから。
962はstructだからガベコレは無関係だぞ
968デフォルトの名無しさん:02/12/13 12:30
structもガベコレされることすら知らない967がいるスレ
structがガベコレ対象だと思い込んでいる968が煽るスレ



structはガベコレされません。
970 :02/12/13 14:09
>>962

これきついね。APIに渡すための構造体を wrap するクラスは全部 pin
するってこと。。。?
>>962
いや、それはstructの使い方が間違っているってことだろう。
アドレスをメソッドに渡したらアドレス(32ビット数値)が残っているだしょ。
IntPtrにキャストしてるんだから。

素直にヒープに取ればいいじゃん。ちなみにpinは関係ないよね。
972962:02/12/13 15:46
>>971
いえ、実は構造体は Win32 の RECT で、メソッドは DirectX の LockRect なんですけどね。
このメソッドはその場で RECT を参照するだけなのでスタックに取っても大丈夫なはずなんです。
ちなみに preventOptimizing への代入を、メソッドを呼ぶ前に持ってきても正しく動きました。
IL 見てないので正確ではないかもしれませんが、アドレス演算子以外の何らかの形で一度も参照されないと変数自体が削除されるみたいなんです。
>>972
うー、そうですか。DirectXは全然わからないので、IL見せてください。
ちなみにこんなコードで実験してみましたが、結果はちゃんと3が返りました。これじゃ実験になってないですか?

-- DLL(cl dll2.cpp /LD)
extern "C" __declspec(dllexport) int WINAPI SomeNativeMethod(CONST RECT* ptr) {
 RECT r;
 CopyMemory(&r, ptr, sizeof(RECT));
 return r.left + r.top;
}

-- Main(csc /unsafe /optimize+ /debug- Class1.cs)
class Class1 {
 struct MyStruct {
  internal int left;
  internal int top;
  internal int right;
  internal int bottom;
  internal MyStruct(int l, int t, int r, int b) {
   left = l;
   top = t;
   right = r;
   bottom = b;
  }
 }
 [System.Runtime.InteropServices.DllImport("C:\\dll2.dll", EntryPoint="_SomeNativeMethod@4")]
 unsafe static extern int SomeNativeMethod(IntPtr ptr);
つづき
 [STAThread]
 unsafe static void Main(string[] args) {
  MyStruct s = new MyStruct(1,2,3,4);
  int i =SomeNativeMethod( new IntPtr( &s ) );
  Console.WriteLine(i);
  // MyStruct preventOptimizing = s; // コメントはずすと正しく動くよ
 }
}
975962:02/12/13 20:35
まず、C#のソースコードです。

D3DLOCKED_RECT lockedRect = new D3DLOCKED_RECT();
RECT rect = Win32Methods.RectFromLTWH( 0, 0, size.Width, size.Height );
texture.GetSurfaceLevel( 0 ).LockRect( ref lockedRect, new IntPtr( &rect ), 0 );
//RECT preventOptimizing = rect;

/*
 size にはテクスチャのサイズが入っています。
 texture.GetSurfaceLevel( 0 ) で、テクスチャの最上位サーフェイスを取得して、
 それをロック、ロックされた領域の情報(アドレスとピッチ)を D3DLOCKED_RECT に受け取ります。
*/
976962:02/12/13 20:42
次に、正常に動く(preventOptimizing を使用している)コードの IL です。

// lockedRect
IL_020e: ldloca.s V_7 // ← lockedRect は V_7 に割り当てられる
IL_0210: initobj [Interop.DxVBLibA]DxVBLibA.D3DLOCKED_RECT

// rect = Win32Methods.RectFromLTWH(...)
IL_0216: ldc.i4.0
IL_0217: ldc.i4.0
IL_0218: ldloca.s V_0 // ← V_0 には size が入っている
IL_021a: call instance int32 [System.Drawing]System.Drawing.Size::get_Width()
IL_021f: ldloca.s V_0
IL_0221: call instance int32 [System.Drawing]System.Drawing.Size::get_Height()
IL_0226: call valuetype [Interop.DxVBLibA]DxVBLibA.RECT Win32Methods::RectFromLTWH(int32,
int32,
int32,
int32)
IL_022b: stloc.s V_8 // ← rect は V_8 に割り当てられる

977962:02/12/13 20:43
// texture.GetSururfaceLevel( 0 )
IL_022d: ldsfld class [Interop.DxVBLibA]DxVBLibA.Direct3DTexture8 Sprites.CartoonMeshRenderer::texture
IL_0232: ldc.i4.0
IL_0233: callvirt instance class [Interop.DxVBLibA]DxVBLibA.Direct3DSurface8 [Interop.DxVBLibA]DxVBLibA.Direct3DTexture8::GetSurfaceLevel(int32)

// LockRect
IL_0238: ldloca.s V_7 // ← V_7 の lockedRect と
IL_023a: ldloca.s V_8 // ← V_8 の rect を渡した IntPtr と
IL_023c: newobj instance void [mscorlib]System.IntPtr::.ctor(void*)
IL_0241: ldc.i4.0 // ← 定数の 0 を使って LockRect を呼び出す
IL_0242: callvirt instance void [Interop.DxVBLibA]DxVBLibA.Direct3DSurface8::LockRect(valuetype [Interop.DxVBLibA]DxVBLibA.D3DLOCKED_RECT&,
native int,
int32)


ちなみに最後の preventOptimizing への代入は見事に消滅していました。
が、rect は無事 LockRect に渡されているので正しく動きます。
978962:02/12/13 20:48
次に、preventOptimizing を使わずに、正しく動かないコードの IL です。
ほとんど同じですが。

// lockedRect
IL_020e: ldloca.s V_7
IL_0210: initobj [Interop.DxVBLibA]DxVBLibA.D3DLOCKED_RECT

// rect = Win32Methods.RectFromLTWH(...)
IL_0216: ldc.i4.0
IL_0217: ldc.i4.0
IL_0218: ldloca.s V_0
IL_021a: call instance int32 [System.Drawing]System.Drawing.Size::get_Width()
IL_021f: ldloca.s V_0
IL_0221: call instance int32 [System.Drawing]System.Drawing.Size::get_Height()
IL_0226: call valuetype [Interop.DxVBLibA]DxVBLibA.RECT Win32Methods::RectFromLTWH(int32,
int32,
int32,
int32)
IL_022b: pop // ←なぜか pop してしまう。 RECT は V_8 に割り当てられず綺麗さっぱり消滅します。
979962:02/12/13 20:51
// texture.GetSururfaceLevel( 0 )
IL_022c: ldsfld class [Interop.DxVBLibA]DxVBLibA.Direct3DTexture8 Sprites.CartoonMeshRenderer::texture
IL_0231: ldc.i4.0
IL_0232: callvirt instance class [Interop.DxVBLibA]DxVBLibA.Direct3DSurface8 [Interop.DxVBLibA]DxVBLibA.Direct3DTexture8::GetSurfaceLevel(int32)

// LockRect
IL_0237: ldloca.s V_7
IL_0239: ldloca.s V_0 // ← なぜか size を渡す。
IL_023b: newobj instance void [mscorlib]System.IntPtr::.ctor(void*)
IL_0240: ldc.i4.0
IL_0241: callvirt instance void [Interop.DxVBLibA]DxVBLibA.Direct3DSurface8::LockRect(valuetype [Interop.DxVBLibA]DxVBLibA.D3DLOCKED_RECT&,
native int,
int32)


と言う感じで、rect が無くなって、指定してもいない size が渡されていました。
rect が無くなるのは最適化の影響ということで仕様としてもいいのですが、
その副作用で size が渡されるのは明らかにバグではないかと思うのですが。
# 下手するとセキュリティホールになり兼ねない気が...

ちなみに、この部分以外にも、構造体のアドレスを渡すところではだいたい再現してました。
うーん、Interop.DxVBLibA.dllも使って975のコードをコンパイルしてみたものの、
再現しませんでした。唯一書けなかったのはWin32Methods.RectFromLTWHなんですが、
これ何ですか?ILとしてもこの部分(の次)で妙なPOPが起きているようですが。。。
とりあえず自分でこんなのを作ったのですが、これを使って、無駄な代入をコメントアウトしても、
こちらでは正しいILのほうが生成されています。

class Win32Methods {
 internal static RECT RectFromLTWH(int l, int t, int w, int h) {
  RECT rect; rect.left = l;
  rect.top = t; rect.right =w; rect.bottom = h;
  return rect;
 }
}
981962:02/12/14 07:36
とりあえず再現する最小限のコードを乗っけます。(行数の関係でかなり押し込みましたが)
問答無用で最初のローカル変数が表示されるようです。
どうやら結構複雑な問題のようで、アドレスを取るだけでは問題は発生せず、
それより前に out パラメータを使ったメソッドを呼び出していると起こるようです。
それが必須条件なのかどうかはわかりませんが。

using System;
using System.Runtime.InteropServices;
public class Class1{
[STAThread] static void Main(string[] args){
int valueToShow = 1024; // なぜかこの値が表示される、数字は何でも良い
int preventOptimizing = valueToShow; // 最適化で消滅するのを防ぐ
// ↑この2行は無くてもかまわない、無い場合は
// ↓ の dummy が表示されるだけ、とにかく最初のローカル変数が表示される。
object dummy; // 型は object である必要はまったく無い、値型でも参照型でも
Dummy( out dummy ); // かまわないが、とにかく out パラメータで渡す。
unsafe{
int valueWantToShow = 1; // 表示されない
// int preventOptimizing2 = valueWantToShow; // しかしこの行を使えば正しく表示される。
ShowValue( new IntPtr( &valueWantToShow ) );
}
}
// 何でも良いがとにかく out で受け取る、代入しないとエラー出るのでとりあえず null をいれておく
// 代入する値は何でもかまわない。
static void Dummy( out object o ){ o = null; return; }
// ポインタの先の値を表示
static void ShowValue( IntPtr p ){
Console.WriteLine( "value = "+Marshal.ReadInt32( p ) );
}
}
>>981
うー、コピペして、.NET Framework 1.0 RTM、SP2、1.1 Final Betaで
試しましたが、いずれもValue=1でした。。。。
983962:02/12/14 11:53
>>982
あれぇ〜〜??
ってことはもしかしてこっちの.NET Frameworkが古いのかも?
SP2当ててなかったっけな・・・?
ShowValue( new IntPtr( &valueWantToShow ) );
のところを
fixed(int* p = &valueWantToShow){
 ShowValue(p);
}
にしたらどう?