( ゚Д゚)ノ Delギコ猫のプログラミング相談室part2
911 :
Delギコ:01/09/20 23:14
∧ ∧ ・・・・。
( ゚Д゚)
|∪ |
〜| | ナンカ ワケワカ
U U
>>905 OnMessageはTApplicationにしかないと思う。
TWinControl全てにあっていいと思うけど
そしたら多重SubClass化なんてくだらない問題も解決かな。
> ところがすべての Windows メッセージに対して、Dynamic メソッドを
> 定義できるため、コントロールのソースがある場合、わざわざ WindowProc を
> 変更する必要はほとんどない
ここ以下がサパーリわかりません??
わからなすぎて、何がわからないのかもわからな・・・
>>907 スンマソン、またーくわからないでし。
罠、消えますの?PMethod(Self)^.自分のMethod??
現在、
>>897で
元に戻す時にTMethod(ナンカ.WndProc) = TMethod(Self.新しいWndProcメソド)
を確認して、Trueなら戻すし Falseなら例外でサブクラス化解除しないよにしてます。
IDE上からなら
サブクラス化、解除不可でCompo削除不可になっても
プロジェクトを閉じて開きなおせばたぶんCompo削除可能なのですが
プログラム上からTFuckCompoClassをCreateしたりFreeしたりすると
やぱりだめでしょうね(そんなことする奴はイネーと思うが)
サブクラス化は各Compo一つに1回だけを心がけるべきかしら。
>>906 事故レス
>>909の方法は間違いだ。途中の順番逆だし
これだと多重にサブクラスされていた場合に対応出来ない。
再帰的に、
WM_DetachProcが送られたら
LParamを見て送信者=受信者でなければ
元に戻してFOldWndProcに同じメッセージを投げつける
メッセージから帰って来たら再度コネクトする
LParamを見て送信者=受信者なら
元に戻して完了
とすればどうだろ
検証してないけど
procedure TFormFucker.FormWndProc(var Message: TMessage);
begin
case Message.Msg of
WM_DetachProc:
begin
TCustomForm(AOwner).WindowProc := FOldFormProc;
if (TFormFucker(LParam) <> Self) then begin //呼び出したのが自分でなければ
FOldFormProc(Message);//さらに解放を続ける
FOldFormProc:=TCustomForm(AOwner).WindowProc ;
TCustomForm(AOwner).WindowProc := FormWndProc;//接続しなおす
end;
end;
else FOldFormProc(Message);
end;
end;
destructor TFormFucker.Destroy;
var msg:TMessage;
begin
msg.Msg :=WM_DetachProc;
msg.WParam:=Longint(FormWndProc);
msg.LParam:=Longint(self);
end;
> ところがすべての Windows メッセージに対して、Dynamic メソッドを
> 定義できるため、コントロールのソースがある場合、わざわざ WindowProc を
> 変更する必要はほとんどない
message指令とか、WM〜メソッドをoverrideするってことかも。
907の説明)サブクラス化を行うコンポを削除すると問題なのは、
自分のメソッド(FormのWindowProcと置き換えていたやつ)
が他のコンポにOldProcみたいなかんじで保存されていて、
インスタンスが破壊された後にも呼び出される事があるってことだと思う。
だからWindowProcを置き換えるメソッドはクラスメソッドにして、
そこから処理本体のメソッドを呼び出すようにするという仕組み。
で、使い終わったら、処理本体でなくて、置き換える前のFormのメソッドを
呼び出すようにしてやる。
インチキをしているのは、クラスメソッドを呼ばせる時、TMethod.Data
に当たる部分のデータを、書き換えてしまうところ。
ここの数値が正当じゃなくても、ちゃんと呼んでくれるみたい。
説明下手でスマソ
そういや昔「ばか者」を意味するfuckerって
名前をつけるのは不適切とかのたまってたのがいたな
916 :
デフォルトの名無しさん:01/09/20 23:54
917 :
Delギコ:01/09/21 00:11
∧ ∧ / ̄ ̄ ̄ ̄ ̄
(゚Д゚*,) < 書いてみた
_φ_⊂)__ \_____
/旦/三/ /|
| ̄ ̄ ̄ ̄ ̄| |
|千葉ピーナッツ|/
 ̄ ̄ ̄ ̄ ̄
こんな感じでなってるよね。
Form1.WndProc
=A.NewProc
begin
・・・
A.FOldProc=B.NewProc
end; begin
・・・
B.FOldProc=C.NewProc
end; begin
・・・
C.FOldProc=サブクラス化しないときのForm1のWndProc
end;
A/B/Cは一応、自分が作れるものとしましょう。
他人が作ったものでも対応できればいいけど、さすがにそりゃ無理でしょ
で、A/B/CのClassは全く別だとしましょう。
TA,TB,TCとでも考えてくださればいいっす。
918 :
Delギコ:01/09/21 00:12
∧ ∧ / ̄
∩(,,゚Д゚) < おもしろい。
⊂,,⌒ ,,つつ. \_
 ̄ ̄ ソンナニ sage ンデモ エエデ(関西風)
Bをサブクラス化から開放したいとき
A.FOldProc:=B.FOldProcする必要があって
それってWM_DetachProcメッセージ伝達で出来るのかしら??
ちょっとイメージできてないです。
というか、Bを開放するときに、Aも一緒にはずしてしまうって事かしら。
でもコンポーネントは配置されているのに
理由もなくサブクラス化されていない物が混じっているのも
ちょっときついかも
そのあとAを開放しようとすると
プログラム側がワケワカな挙動しないかな。
>Delギコさん
新スレ立てるとき、ここの1みたく「その他のプログラム」って書くと
またVBの質問とか出てきそうだからやめよう。
検討済みだったらスマソ。
921 :
デフォルトの名無しさん:01/09/21 08:11
多段サブクラス取り外し問題は
取付順
↓ objA ─────────────── WndProc → FoldwndProc
↑ │
↓ objB ────────── WndProc → FoldwndProc │
↑ │
↓ objC ───── WndProc → FoldwndProc │
↑ │
↓ objD WndProc → FoldwndProc │
↑ │
msg ……………> (サブクラス先の.WndProc )←──┘
こういうふうになっていると安全に取り外せるのは objDだけ
objAを取り外したい場合は objA,B,Cの順に取り外さなければいけない
これはメッセージの流れる順だから
取り外せというメッセージを送ればいい。
そのメッセージを処理するWndProc内部で取り外し処理をしては
送ったメッセージが自分のメッセージでなければ
FoldWndProcを通じてルートを遡らせてゆき
そのFoldWndProcが帰って来たら再度接続しなおす。
メッセージさえ共通にしておけばいいから複数のオブジェクトを設計する場合も
それほど難しい問題は起きない。
検証した。 問題なく取り付け取り外しできるように見えるぞ
const WM_DatachProc = WM_USER;
type
TtestLabel = class(TLabel)
public
FoldWndProc:TWndMethod;
constructor Create(AOwner: TComponent);override;
destructor Destroy;override;
procedure MyWndProc(var Message: TMessage);
end;
constructor TtestLabel.Create(AOwner: TComponent);
begin inherited;
if (AOwner is TCustomForm) then
begin
FOldWndProc := TCustomForm(AOwner).WindowProc;
TCustomForm(AOwner).WindowProc := MyWndProc;
end else begin
FOldWndProc := nil;
end;
end;
destructor TtestLabel.Destroy;
var msg:TMessage;
begin
msg.Msg:=WM_DatachProc;
msg.WParam:=longint(self);
(Owner as TCustomForm).WindowProc(msg);
inherited;
end;
procedure TtestLabel.MyWndProc(var Message: TMessage);
begin
case Message.Msg of
WM_DatachProc:begin
(Owner as TCustomForm) .WindowProc := FOldWndProc;
if ( Message.WParam <> LongInt(Self)) then
begin
FOldWndProc(Message);//さらに解放を続ける
FOldWndProc:=(Owner as TCustomForm) .WindowProc;
(Owner as TCustomForm) .WindowProc:= MyWndProc;
end else FOldWndProc:=nil;
end;
WM_CHAR: begin //コンポーネントの動作チェック用
text:=Char(Message.WPARAM);
if assigned(FoldWndProc) then FoldWndProc(Message);
end;
else if assigned(FoldWndProc) then FoldWndProc(Message);
end;
end;
procedure Register;
begin RegisterComponents('Samples', [TtestLabel]);
end;
end.
923 :
デフォルトの名無しさん:01/09/21 09:02
という事でココをご覧のコンポーネント作家さん
WM_DatachProc = WM_USER;
をサブクラス取り外し用メッセージという事にして
WParamでSelfを送るという約束にしましょう。
LParamは空きとして
924 :
デフォルトの名無しさん:01/09/21 09:07
さらにWindowsへのサブクラスの場合も考えて
LParam にはプロセスユニークと思われる番号(とりあえずプロセスID)が
与えられる事にしましょう。
おっと、
>>922 のコードでは
FOldWndProc がnilかどうか確認せずに使ってる個所が
何箇所かあるから修正してね
>>922-925
ふと思ったんだが、
WM_USERだとすでに使われていて別の意味を持つ場合もあると思うから、
RegisterWindowMessage('WM_SubclassFreeNotify');
みたいにして使った方が(・∀・)イイ!と思われ。
もしくはWM_USER+222みたいにするとか。222の意味は2chということで:-)
WM_USERってVCL自体で使ってたような。はまったことある。
WM_APP以降にせんと安心できなかったな。
RegisterWindowMessageがやはり無難な感じ
928 :
デフォルトの名無しさん:01/09/21 09:50
ではサブクラス解放についてのまとめ
WM_DatachProc = RegisterWindowMessage('WM_SubclassFreeNotify');
WParam,LParam はユニークな値が入る
この2つの値で送信者が自分かどうか判断し
自分でなければリンクを解放して下位にメッセージを送り
メッセージが帰って来たらリンクを再接続する
送信者が自分ならリンクの解放だけを行う
VCL上のサブクラス取り外し
WParam で selfが渡される WParam = LongInt(self)
LParamは無視してよい
Win上のサブクラス取り外し
LParamでプロセスID
WParamはプロセス内ユニークな値(メソッドアドレス等それぞれのプロセスで管理)
929 :
Delギコ:01/09/21 09:51
∧∧ / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
@' ― (,,゚Д゚) < 正規表現はわからんちー。
し― し-J \___________
2chのどこかで正規表現すれがあったような気もする
>>921さんは
>>922さん?
>こういうふうになっていると安全に取り外せるのは objDだけ
これで妥協してしまうのだったら
問題は非常に簡単なんですけどね。
> objAを取り外したい場合は objA,B,Cの順に取り外さなければいけない
??なんかわからなくなってきました。
objAを取り外したい場合はobjBのFoldWndProcを
サブクラス先の.WndProcに接続しなきゃいけないですよね。
> そのFoldWndProcが帰って来たら再度接続しなおす。
イチドサブクラス化解除させてから再度サブクラス化させるってことかな
>>922のコードはイマからみてみます。
×Datach
○Detach
×objAを取り外したい場合は objA,B,Cの順に取り外さなければいけない
○objAを取り外したい場合は objD,C,Bの順に取り外さなければいけない
>objAを取り外したい場合はobjBのFoldWndProcを
>サブクラス先の.WndProcに接続しなきゃいけないですよね。
結果的にはそういう事だけど、
それに拘るからハマルんだよ
基本的にobjAからは objBが見えない。確実に割り出す方法はないんだよ。
サブクラスがobjA,objBの2段だけなら サブクラス元のメソッドポインタから割り出せるけど
さらにサブクラスされているともうダメ
だから、メッセージを使う方法が一番安全で確実だと皆言ってるじゃないか
933 :
Delギコ:01/09/21 10:15
∧ ∧ /
(,,゚Д゚)< こりゃまたすごいや。
|つ つ \
@ |
∪ ∪
動作コードみてようやくわかりました。
サンサンサンクスコクスコクスコーーーー
>>921の図でいうと
objAを取り外す場合
objAからメッセージを投げる
objDに伝わる
objDのサブクラス化を解除
objDからobjCに連絡
objCに伝わる
objCのサブクラス化を解除
objCからobjBに連絡
objBに伝わる
objBのサブクラス化解除
obfBからobfAに連絡
objAに伝わる
objAのサブクラス化解除
objAは自分自身なので何もしない
objAの処理が終わったので
objBに処理が戻り再度SubClass化
objBの処理が終わったので
objCに処理が戻り再度SubClass化
objCの処理が終わったので
objDニ処理が戻り再度SubClass化
こういう事になっているわけですね。
934 :
Delギコ:01/09/21 10:27
∧ ∧ / ̄ ̄ ̄ ̄ ̄ ̄ ̄
(,,゚Д゚) < んまー。するどい
>>932 | つつヾ \_______
〜| | ユルシテヨ
∪∪
> 結果的にはそういう事だけど、
> それに拘るからハマルんだよ
ええ、しっかりと浜りました。
みっちりときっちりと。
> 基本的にobjAからは objBが見えない。確実に割り出す方法はないんだよ。
そうっすね。
ということは、他人の作ったものが混じった場合、例えばここのCompo
http://www.psn.ne.jp/~nagayama/program/0017.html (ごめんねサイト作者さん)
この仕組みは動作しないから…一体どうなるんだろ。
…テストをしている限りは変な挙動はしていないみたい。
ちゃんとtestLabelは取り外せますね。
正しいのかな?
> サブクラスがobjA,objBの2段だけなら サブクラス元のメソッドポインタから割り出せるけど
> さらにサブクラスされているともうダメ
ですねー。
> だから、メッセージを使う方法が一番安全で確実だと皆言ってるじゃないか
やっとわかたでし。
935 :
デフォルトの名無しさん:01/09/21 10:39
再度 サブクラス解放についてのまとめ >>コンポーネント作家の方々へ
サブクラスを利用するコンポーネントは以下の手順で解放する事
var WM_DetachProc:Cardinal; をローカル変数として定義し
コンポーネントの初期化部で
initialization
WM_DetachProc := RegisterWindowMessage('WM_SubclassFreeNotify');
end.
とする。
サブクラス解放時にはこのメッセージIDで
WParam,LParam はユニークな値を入れて サブクラス先に送信する
それを受信したWindowProcでは、
この2つの値で送信者が自分かどうか判断し
自分でなければリンクを解放して下位にメッセージを送り
メッセージが帰って来たらリンクを再接続する
送信者が自分ならリンクの解放だけを行う
VCL上のサブクラス取り外し
WParam で selfが渡される WParam = LongInt(self)
LParamは無視してよい サンプルコード
>>922 Win上のサブクラス取り外し
LParamでプロセスID
WParamはプロセス内ユニークな値(メソッドアドレス等それぞれのプロセスで管理)
注意: WM_DetachProc は定数ではないので case では使えない ifで判断する事
>>934 リンク先みてみた。
これが簡単に暴走しない理由は、
FNewWndProc := MakeObjectInstance(WndProc);
とサンクを使っていて、オブジェクト解放時にこのサンクを解放していないからじゃないかと思う
937 :
Delギコ:01/09/21 11:02
∧ ∧ / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
( ゚Д゚) < ほかの自作FormフックCompoも試した
.=| |==U=U==.| |= \___________
| | | | | | 普通にVCLでフック解除するヤツだよ
| | ノU U. | |
| | .| |
testLabelを削除された時に
暴走はしないのですが
自作の方のサブクラス化は解除されてしまうます。
自作の方は正しくサブクラス化解除できないときは
例外を出すようにしてるからいいけど
タブン、マトモに削除するとWndProcがどこかに逝ってしまい
暴走するだろーな。
WM_DetachProc が流れた所で
安全にサブクラス化解除されない場合は例外発生して
元に戻るようにできないかいニャ。
考え中.....
そこまで拘らなくてもいいって肝するけどー。
938 :
Delギコ:01/09/21 11:04
∧ ∧ /なんにせよ
( ゚Д゚) < 教えてくれたデフォルトの名無しさんズ。
ノつノつ \ありがとーう。
( 人
ソ )
ノ ノ
( 人 ネジッテ ミマシタ
ソ )
ノ ノ
UU
>>895 最初の例が間違えてたっす。スマソ。
s/(\-\-|==)+/$1/g; の場合
「-」奇数→「---」
「-」偶数→「--」
ですな。例では「-=」ともに偶数だから結果は
895が書いてる通りになります。
940 :
デフォルトの名無しさん:01/09/21 11:09
いまさらですが、サブクラスとは具体的にどういう作業を指すのでしょうか。
オブジェクト指向の一部ですか?それとも
単にテクニックの一つでしょうか。
サブクラスとWinProcとはどういう関係がありますか。
つーか、WinProcは何者ですか。
941 :
デフォルトの名無しさん:01/09/21 11:16
Delphiでは、メッセージハンドラとしてメッセージマップなんかより、
ずっと綺麗にメッセージを隠蔽してるから、使わなくて問題無い。
また、Delphiでコールバック関数やメッセージ使うと、
あっという間に超読めないコードになる。
だから、メッセージ操作コード出さないでね>>Delギコ
942 :
Delギコ:01/09/21 11:23
( ヽ ―――― ○ ――――
, ⌒ヽ ( ) // | \
( ' ( ヽ⌒ヽ 、 / / | \
ゝ `ヽ( ) | (⌒ 、
( 、⌒ ヽ ( ヽ
( (⌒ ) (
( Y⌒ ヽ
( `)
ゝ ノ ノ
_________________________________________________________________________________________
〜〜 〜〜 〜〜〜 〜 〜〜 〜〜 〜 〜〜 〜
〜〜 〜〜 〜〜 〜〜〜 〜
〜 〜〜 〜〜 〜〜 〜〜 〜〜 〜〜〜
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.... ∧ ∧ .... ..... .... .....
.... (,,゚Д゚) .. .... .... .....
.... | ∪ .... ... ... .
.... 〜 | ナツガ オワッタ スレ モ オワッタ ....
.... ∪∪
.... アツイ オモイデ サヨウナラ .... .... ...
新スレ立てました。サブクラス化などの続きはこちらで、、
( ゚Д゚)ノ Delギコ猫のプログラミング相談室part3
http://piza2.2ch.net/test/read.cgi?bbs=tech&key=1001039863
ああ、そうか、
このメッセージが経路を辿る時に途中で解放せずにそのまま渡されて来る場合もある訳で
経路の全てがこのメッセージをサポートしてるかどうかチェックする方法が無いといけないのか
という事で、このメッセージを受け取った時のサブクラス先のポインタが自分が設定した時の
状態に戻っていなければ・・・・・
どうしようもないかな?
せいぜいメッセージを出して別の何もしないコンポを動的に作成してそいつを割り当てておくしかないかも
という事でコンポ作家の皆さん
>>935 をよろしく
945 :
デフォルトの名無しさん:01/09/21 11:53
つまり、コントロールに送られたウィンドウメッセージを
最初に受け取るのが WinProc 関数であり、
これを別の関数に置換して、そちらにメッセージが
流れるように仕向ける操作を「サブクラス化」と呼ぶわけですか。
>>939 ぁぁ納得したです
これで正規表現はバッチリだ(嘘
947 :
デフォルトの名無しさん:01/09/21 12:08
>>941何がいいたいんだ?
>頻繁に必要になるものでもないが、必要なときには使うしかあるまい?
Delギコ生意気。使わずにできるぞ。
サブクラスの作成でつまずいてるんだろ。それがメッセージのせいって分からんのか。
分からんのだったら、人にアドバイスするな。
マターリいこうぜ
∧ ∧ / ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
(,,゚Д゚) < え〜、牛乳いかがっすかー。
./\品品昌_ \___________
( U__| 雷印 |
.U U ̄ ̄ ̄
カルシウム不足の方が1名おられるようで
他のお客様のご迷惑になりますので,,,
牛乳飲んどけ。
折れもカルシウム不足かも。ノンどくか。
でも、ウシって今・危ニャーかも??
>>949 牛乳には狂牛病の原因と考えられているプリオンは含まれません。
神経系の体液が関与しない限り安全です。
951 :
デフォルトの名無しさん:01/09/21 21:11
終いには「Delギコ猫のプログラミング相談室」なんていう書籍が出そうだね(w
952 :
デフォルトの名無しさん:01/09/22 06:13
なんで”サブクラス化”と言うのでしょうか?
サブクラスと言うと、子クラスを連想します。
数学の集合辺りの用語とか聞いた
>サブクラスと言うと、子クラスを連想します
合ってるやん
新スレあるのにageるとはこれいかに
こっちのスレに書かしてもらいます。
なんとなく実装の改良案。
destructor TTestLabel.Destroy;
var
TempWindowProc: TWndMethod;
Msg: TMessage;
begin
TempWindowProc := TCustomForm(Owner).WindowProc;
TCustomForm(Owner).WindowProc := FOldWindowProc;
Msg.Msg := WM_DetachProc;
Msg.LParam := 0;
Msg.WParam := WPARAM(Self);
Msg.Result := 0;
TempWindowProc(Msg);
inherited Destroy;
if Msg.Result = 0 then
raise Exception.Create('サブクラス化解除がおかしいですよ〜');
end;
procedure TTestLabel.MyWindowProc(var Msg: TMessage);
begin
if Msg.Msg = WM_DetachProc then
begin
if Msg.WParam = WPARAM(Self) then
begin
Msg.Result := 1;
end
else
begin
FOldWindowProc(Msg);
FOldWindowProc := TCustomForm(Owner).WindowProc;
TCustomForm(Owner).WindowProc := Self.MyWindowProc;
end;
end
else
FOldWindowProc(Msg);
end;
/\ ________
/ギッコー /
/____\ < 新スレでやろーう
| ゚Д゚| \
ノ| || || || |し  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
sageるよ
保守
にゃんまげ
保守