How to send / receive windows messages between VB6 and C #?

I know that I can receive messages with the code below in C #, how can I send to vb6 and receive in vb6 and send with 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); } 
+3
source share
3 answers

Before starting, I would like to say that I agree with MarkJ. COM Interop will make your life much easier and will not require you to work.

SendMessage is the preferred way to call one or the other using Windows Message handlers. PostMessage is difficult to use with complex types, because the lifetime of the data associated with a Windows message in .NET and VB6 is difficult to control while the message is queued and the message completion is unknown unless you implement some form of callback mechanism.

Anyway, sending Windows messages from anywhere to the C # window just requires that you know the HWND of the C # window that should receive the message. Your snippet looks correct as a handler, except that the switch statement must first check the Msg parameter.

 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); } 

Getting a window handle from C # Form, Window, or Control can be done using the .Handle property.

Control.Handle Property @MSDN

Suppose you have a way to port a window handle from C # to VB6.

From VB6, the signature of the SendMessage window is as follows:

 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 

To call it, you would do something like the following. For brevity, uMsg is WM_APP (32768), wParam / lParam is 0:

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

Similarly, sending a message with C # is similar. To get HWND windows in VB6, use the .hWnd property of the window in VB6, which should receive the message.

It looks like you are using your own set of message identifiers, there are additional steps for handling custom message identifiers in VB6. Most people handle this by subclassing the form window and using the subclass procedure to filter these messages. I have included sample code to demonstrate C # on VB6, since handling custom messages is more complicated in VB6.

Here is the source code for a couple of test programs, a C # library, and a VB6 Forms project. The C # library must be configured with "Register for COM Interoperability" and "Make the Assembly COM-Visible" in the project settings.

First, the C # library. This library contains one COM component that will be visible to VB6 as the type CSMessageLibrary.TestSenderSimple. Note that you need to enable the P / Invoke signature (e.g. VB6 method) for SendMessage.

 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); } } 

Now, on the VB6 side, you will need to add subclass support to the window. In addition to the best solutions that can be applied for each window, we’ll just move on to something that shows how to configure one window.

First, to run this sample, make sure you create a C # application and register it correctly with COM. Then add the link from VB6 to the .tlb file, which is next to the C # output. You will find this in the bin / Debug or bin / Release directory in a C # project.

The following code should be placed in the module. In my test project, I used a module called "Module1". The following definitions should be indicated in this module.

WM_APP - used as the user identifier of the message, which will be without interference.
GWL_WNDPROC - a constant that is used for SetWindowLong to request modification of a window handler.
SetWindowLong is a Win32 function that can change special attributes in windows.
The CallWindowProc function is Win32, which can send Windows messages to the designated window handler (function).
SubclassWindow - a module function for setting up a subclass for a selected window.
UnsubclassWindow - a module function for dropping a subclass for a selected window.
SubWndProc is a module function that will be inserted through a subclass so that we can intercept Windows user messages.

 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 

In the test form, I hooked up an instance of the C # test object as a member of the form. The form includes a button with the identifier "Command1". The subclass is configured when the form is loaded, and then deleted when the form is closed.

 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 

Sending numeric arguments that fit in 4 bytes is trivial, like in wParam or lParam. However, sending complex types and strings is much more complicated. I see that for this you have created a separate question, so I will give answers to it.

REF: How to send a structure from C # to VB6 and from VB6 to C #?

+5
source

To send to VB6 you need to use an API call ( SendMessage or PostMessage). To get into VB6 you need to use a subclassification (complicated - here is the best way I know ).

Have you considered instead of COM Interop ? This is a much easier way to communicate between VB6 and C # than Windows messages.

+3
source

Use the PostMessage Windows API function.

At the beginning of your class:

 [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; 

Then process the message by overriding the WndProc class.

 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. 

Then in your Enter event:

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

This works because you force your own processing after Windows performs the default processing of the Enter event and the associated mouse processing. You put your request in a message queue, and it is processed in turn in the WndProc event. When your event is triggered, you will make sure that the current window is a text field and select it, if any.

+1
source

All Articles