4

C# で以下のコードを使用してメッセージを受信できることはわかっていますが、vb6 に送信し、vb6 で受信し、vb6 から送信するにはどうすればよいですか?

    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    protected override void WndProc(ref Message m)
    {

        int _iWParam = (int)m.WParam;
        int _iLParam = (int)m.LParam;
        switch ((ECGCardioCard.APIMessage)m.WParam)
        {
            // handling code goes here
        }
        base.WndProc(ref m);
    }
4

3 に答える 3

6

始める前に、私は MarkJ に同意します。COM Interop はあなたの生活をずっと楽にし、それほど多くの作業をする必要はありません。

SendMessage は、Windows メッセージ ハンドラーを介して一方または他方を呼び出すための推奨される方法です。.NET と VB6 の両方で Windows メッセージに関連付けられたデータの有効期間は、メッセージがキューに入れられている間は管理が難しく、なんらかの形式のコールバック メカニズムを実装しない限り、メッセージの完了は不明であるため、PostMessage を複雑な型で使用するのは困難です。 .

とにかく、どこからでも Windows メッセージを C# ウィンドウに送信するには、メッセージを受信する C# ウィンドウの HWND を知っている必要があります。switch ステートメントが最初にMsgパラメータに対してチェックする必要があることを除いて、スニペットはハンドラーとして正しいように見えます。

protected override void WndProc(ref Message m)
{

    int _iWParam = (int)m.WParam;
    int _iLParam = (int)m.LParam;
    switch ((ECGCardioCard.APIMessage)m.Msg)
    {
            // handling code goes here
    }
    base.WndProc(ref m);
}

C# フォーム、ウィンドウ、またはコントロールからウィンドウ ハンドルを取得するには、.Handle プロパティを使用します。

Control.Handle プロパティ @ MSDN

ここでは、ウィンドウ ハンドルを C# から VB6 に転送する何らかの方法があると仮定します。

VB6 から、SendMessage ウィンドウの署名は次のとおりです。

Private Declare Function SendMessage Lib "USER32.DLL" _
    (ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long

それを呼び出すには、次のようにします。簡潔にするために、uMsg は WM_APP (32768)、wParam/lParam は 0 です。

Dim retval As Long
retval = SendMessage(hWnd, 32768, 0, 0)

同様に、C# からのメッセージの送信も同様です。VB6 でウィンドウの HWND を取得するには、メッセージを受信する必要がある VB6 のウィンドウの .hWnd プロパティを使用します。

独自のメッセージ識別子セットを使用しているように見えるため、VB6 でカスタム メッセージ識別子を処理するための追加の手順があります。ほとんどの人は、フォーム ウィンドウをサブクラス化し、サブクラス プロシージャを使用してこれらのメッセージをフィルタリングすることで、これを処理します。VB6 ではカスタム メッセージの処理が難しいため、C# から VB6 へのデモンストレーションを行うサンプル コードを含めました。

これは、C# ライブラリと VB6 フォーム プロジェクトのペアのテスト プログラムのソース コードです。C# ライブラリは、プロジェクト設定で「COM 相互運用に登録」および「アセンブリを COM 可視化」で構成する必要があります。

まずはC#ライブラリ。このライブラリには、タイプ「CSMessageLibrary.TestSenderSimple」として VB6 に表示される単一の COM コンポーネントが含まれています。SendMessage の P/Invoke 署名 (VB6 メソッドなど) を含める必要があることに注意してください。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace CSMessageLibrary
{
    [ComVisible(true)]
    public interface ITestSenderSimple
    {
        // NOTE: Can't use IntPtr because it isn't VB6-compatible
        int hostwindow { get; set;}
        void DoTest(int number);
    }

    [ComVisible(true)]
    public class TestSenderSimple : ITestSenderSimple
    {
        public TestSenderSimple()
        {
            m_HostWindow = IntPtr.Zero;
            m_count = 0;
        }

        IntPtr m_HostWindow;
        int m_count;

        #region ITestSenderSimple Members
        public int hostwindow 
        {
            get { return (int)m_HostWindow; } 
            set { m_HostWindow = (IntPtr)value; } 
        }

        public void DoTest(int number)
        {
            m_count++;

            // WM_APP is 0x8000 (32768 decimal)
            IntPtr retval = SendMessage(
                m_HostWindow, 0x8000, (IntPtr)m_count, (IntPtr)number);
        }
        #endregion

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        extern public static IntPtr SendMessage(
          IntPtr hwnd, uint msg, IntPtr wparam, IntPtr lparam);
    }
}

ここで、VB6 側で、ウィンドウをサブクラス化するためのサポートを追加する必要があります。ウィンドウごとに適用できるより良い解決策は別として、単一のウィンドウをセットアップする方法を示すものを使用します。

まず、このサンプルを実行するには、C# アプリケーションをビルドし、COM に正しく登録していることを確認してください。次に、VB6 からの参照を C# 出力の横にある .tlb ファイルに追加します。これは、C# プロジェクトの下の bin/Debug または bin/Release ディレクトリにあります。

次のコードをモジュールに配置する必要があります。私のテスト プロジェクトでは、「Module1」というモジュールを使用しました。このモジュールでは、次の定義に注意する必要があります。

WM_APP - 干渉のないカスタム メッセージ識別子として使用されます。
GWL_WNDPROC - SetWindowLong がウィンドウ ハンドラーへの変更を要求するために使用される定数。
SetWindowLong - ウィンドウの特別な属性を変更できる Win32 関数。
CallWindowProc - Windows メッセージを指定されたウィンドウ ハンドラー (関数) にリレーできる Win32 関数。
SubclassWindow - 指定されたウィンドウのサブクラス化をセットアップするためのモジュール関数。
UnsubclassWindow - 指定されたウィンドウのサブクラスを破棄するモジュール関数。
SubWndProc - カスタム ウィンドウ メッセージをインターセプトできるようにするために、サブクラス化によって挿入されるモジュール関数。

Public Const WM_APP As Long = 32768
Private Const GWL_WNDPROC = (-4)
Private procOld As Long

Private Declare Function CallWindowProc Lib "USER32.DLL" Alias "CallWindowProcA" _
    (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal uMsg As Long, _
    ByVal wParam As Long, ByVal lParam As Long) As Long

Private Declare Function SetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" _
    (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Public Sub SubclassWindow(ByVal hWnd As Long)
    procOld = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf SubWndProc)
End Sub

Public Sub UnsubclassWindow(ByVal hWnd As Long)
    procOld = SetWindowLong(hWnd, GWL_WNDPROC, procOld)
End Sub

Private Function SubWndProc( _
        ByVal hWnd As Long, _
        ByVal iMsg As Long, _
        ByVal wParam As Long, _
        ByVal lParam As Long) As Long

    If hWnd = Form1.hWnd Then
        If iMsg = WM_APP Then
            Dim strInfo As String
            strInfo = "wParam: " & CStr(wParam) & vbCrLf & "lParam: " & CStr(lParam)

            Call MsgBox(strInfo, vbOKOnly, "WM_APP Received!")

            SubWndProc = True
            Exit Function
        End If
    End If

    SubWndProc = CallWindowProc(procOld, hWnd, iMsg, wParam, lParam)
End Function

テスト フォームでは、テスト C# オブジェクトのインスタンスをフォームのメンバーとして関連付けました。フォームには、ID が「Command1」のボタンが含まれています。サブクラスは、フォームが読み込まれるときにセットアップされ、フォームが閉じられるときに削除されます。

Dim CSharpClient As New CSMessageLibrary.TestSenderSimple

Private Sub Command1_Click()
    CSharpClient.DoTest (42)
End Sub

Private Sub Form_Load()
    CSharpClient.hostwindow = Form1.hWnd
    Module1.SubclassWindow (Form1.hWnd)
End Sub

Private Sub Form_Unload(Cancel As Integer)
    CSharpClient.hostwindow = 0
    Module1.UnsubclassWindow (Form1.hWnd)
End Sub

wParam または lParam として、4 バイトに収まる数値引数を送信するのは簡単です。ただし、複雑な型と文字列を送信するのははるかに困難です。そのための別の質問を作成したようですので、そちらで回答します。

REF: 構造体を C# から VB6 に、VB6 から C# に送信するにはどうすればよいですか?

于 2009-11-24T20:30:04.593 に答える
3

VB6で送信するには、API呼び出し( SendMessageまたはPostMessage)を使用する必要があります。VB6で受信するには、サブクラス化を使用する必要があります(複雑です-これが私が知っている最良の方法です)。

代わりにCOM相互運用機能を使用することを検討しましたか?これは、WindowsメッセージよりもVB6とC#の間で通信するためのはるかに簡単な方法です。

于 2009-10-29T17:46:57.920 に答える
1

PostMessage Windows API 関数を使用します。

クラスの始めに:

[DllImport("User32.dll", EntryPoint="PostMessage")]
private static extern int PostMessage(int hWnd, int Msg, int wParam, int lParam);

const int WM_USER = 0x0400;
const int CM_MARK = WM_USER + 1;

次に、クラスの WndProc をオーバーライドしてメッセージを処理します。

protected override void WndProc(ref Message m)
{
  if (m.Msg == CM_MARK) {
    if (this.ActiveControl is TextBox) {
      ((TextBox)this.ActiveControl).SelectAll();
    }
  }
  base.WndProc(ref m);
} // end sub.

次に、Enter イベントで:

private void txtMedia_Enter(object sender, EventArgs e)
{
  PostMessage(Handle.ToInt32(), CM_MARK, 0, 0);
} // end sub.

これが機能するのは、Windows が Enter イベントとそれに関連付けられているマウス処理の既定の処理を行った後に、カスタム処理を強制的に実行するためです。要求をメッセージ キューに入れると、WndProc イベントで順番に処理されます。イベントが呼び出されたら、現在のウィンドウがテキスト ボックスであることを確認し、テキスト ボックスの場合は選択します。

于 2011-05-06T13:31:57.683 に答える