始める前に、私は 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# に送信するにはどうすればよいですか?