読者です 読者をやめる 読者になる 読者になる

★ The Tsuchinoko News 2 (つちのこ通信2) ★

重要な話から、どうでもいいことまで。ほとんど役に立たないことを書き連ねています。

【PC】VB6 から VB2010 へ移行(その4)プロセス間通信(VB6での受信)

IT雑感

f:id:tsuchinoko118:20120428083242j:image:w560
前回のプログラムで、送信された文字列のメッセージは、受信できなければ意味がない。では受信する API とか コントロールがあるのか、というと VB6 にも VB2010 にもない(笑)

仕方がないのでサブクラス化を行って受信することにする。

VB6にしてもVB2010にしても、フォームはクラスでもある。フォームクラスには、プロパティやメソッドなど、あらかじめ決められた機能が提供されるが、この機能群にないことするために「引っかけて、横道にそれて、こっちの道に」ということをするのがサブクラス化。ちょうど、本当なら真っ直ぐおうちに帰るはずなのに、ナンパにあって、ちょっとくっついていってしまい予定(仕様)にないことをする、という感じで、ナンパ=サブクラス化と思えばわかりやすい(わかりにくいかも(笑))

サブクラスの中で、送られてきた文字列のメッセージを処理する。

Private Declare Function CallWindowProc Lib _
	"user32" (ByVal oldproc As Long, _
		  ByVal hwnd As Long, _
                  ByVal msg As Long, _
                  ByVal wParam As Long, _
                  ByVal lParam As Long) As Long

Private Declare Function GetWindowLong Lib _
	"user32" (ByVal hwd As Long, _
		  ByVal NIndex As Long) As Long

Declare Function SetWindowLong Lib _
	"user32" (ByVal hwnd As Long, _
		  ByVal NIndex As Long, _
                  ByVal dwNewLong As Long) As Long
Const GWL_WNDPROC = (-4)


public OldWndProc as long

public strMsg as string

const pmSTART = &h0
const pmDATA = &h1
const pmEND = &h2

Public sub 前準備()


    'サブクラス化	
  OldWndProc = GetWindowLong("メッセージを待ち受ける窓のハンドル".hwnd, GWL_WNDPROC)
    SetWindowLong "メッセージを待ち受ける窓のハンドル".hwnd, _
                   GWL_WNDPROC, AddressOf WndProc  

end sub 
Public Function WndProc(ByVal hWnd As Long, _
                        ByVal msg As Long, _
                        ByVal wParam As Long, _
                        ByVal lParam As Long) As Long

    
  'PostMessage されると、ここに飛んでくる。
	
    if msg = "適当な共有名" then

	select case wParam

		case pmSTART
		    'メッセージバッファをクリア(送信開始)
		    strMsg = ""
                    WndProc = 0
                    Exit Function
			
		case pmDATA

		    'メッセージバッファに追加(送信)
		    strMsg = strMsg & chr(lParam)
                    WndProc = 0
                    Exit Function

		case pmEND

		   '受信完了(送信終了)				
		   '========================
                   '
                   ' strMsg が 送られてきた
          ' メッセージなので
          ' 適宜解析するなりする
                   '
		   '========================
                    WndProc = 0
                    Exit Function

        end select

    end if

    'デフォルトメッセージ処理をする
    WndProc = CallWindowProc(OldWndProc, hwnd, msg, wParam, lParam)

End Function

Public sub 後の処理()


    'サブクラス化を終了する	
    SetWindowLong "メッセージを待ち受ける窓のハンドル".hwnd, GWL_WNDPROC, OldWndProc

end sub 

sub前準備を最初に呼び出し、
oldWndProc にもともとのフォームの処理を保持させて
横道である WndProcサブルーチンにそれるようにセッティングする。

こうすると 送信側から PostMessage されたメッセージが、WndProc サブルーチンに送られるので、ここで受信の処理を行う。
筆者は、3つの勝手コマンド pmSTART,pmDATA,pmEND で、変数msgStr に 送信されてきた文字をためこんで pmEND を受け取ったら、解析なり実行なり、機能の起動なり、という処理を行うようにしている。

WndProc で自分とは無関係の(PostMessageの処理)以外のものが来たら
oldWndProc で保存しておいた、本来のフォームの処理を行うようにする。

最後に、用事が終わったら後処理として、oldWndProc に戻してあげる。

これで受信ができるようになる。

気をつける点として このやり方をすると VB6 の IDE(統合開発環境)で ステップイン/アウトのデバッグなんかをやりたくなるが、うまくいかないことも多い。ハングアップしたり、事情で強制終了したりすることも増える(笑)きちんと設計してからの方が良さそうだ。

ソースを見るとわかるとおり、前回の送信も結構端折っていたりするので、そのままコピペでは動かないが、おおよそ、このような感じ。
それでも、ひどく、ややこしい。
これは、サブクラス化という技法を使うのに、WinAPI を使っているからで、たいへん汚らしいプログラムになりがちだ。

これが VB2010 になると、もっとシンプルになったりする。
VB2010 では、さらにクラスを継承したり、機能(プロパティやメソッド)を追加したり、平行にジャンプさせたりがやりたい放題になっているので、VB6 のような無理矢理感のあるサブクラス化をしなくても、WndProcが書けてしまったりする。このお話は、また次回に・・・