65.9K
CodeProject 正在变化。 阅读更多。
Home

VB.NET、VB6 和 C# 通过窗口消息传递实现进程间通信

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (17投票s)

2004 年 5 月 4 日

2分钟阅读

viewsIcon

239857

downloadIcon

5860

文章概述了使用窗口消息传递在 VB6、VB.NET 和 C# 应用程序之间进行通信的方法。

引言

关于 VB6 进程间通信的文章有很多,关于 .NET 进程间通信的文章也有很多。 但将托管和非托管环境混合用于进程间通信则很有趣。 在解决了一些 VB6 问题后,我终于成功了。 :-)

背景

我的公司目前正在 .NET 中开发新的应用程序,但我们仍然需要支持我们的(主要公司应用程序)旧版 VB6 应用程序。 我们已经开始使用从 VB6 到 VB.NET 组件的 COM 互操作,但在尝试从彼此自动化应用程序时遇到了一些错误。 四处查看后,我认为窗口消息传递独立于 VB 和 .NET 环境。 于是我开始了代码示例和相关解释的搜索。 有些解释了 VB6 消息传递,有些解释了 .NET 消息传递,但没有找到任何两者都涉及的。

使用代码

有关 VB.NET 子类代码的解释,请参阅这篇 CodeProject 文章。 我直接从这里获取了代码,认为没有必要再次解释。

VB6:窗体界面

  Private Sub Form_Load()
    ....
    'Create custom window and start listening to window messages.
    modMessaging.InitWindowMessaging
  End Sub

  Private Sub Form_Unload(Cancel As Integer)
    'Tear down custom message handling and pass 
    'back to original message handler i.e this form
    modMessaging.StopWindowMessaging
  End Sub

VB6:消息传递

  ' Function to create custom window and setup Message Listening
  Public Function InitWindowMessaging()

    '\\This statement creates the new window
    hWindowHandle = CreateWindowEx(0, "STATIC", VB6_WINDOWTITLE_SERVER, _
      0, 0, 0, 0, 0, 0, 0, App.hInstance, ByVal 0&)

    '\\ This statement sets the message handling to the
    '\\ProcessWindowMessages function defined later.
    ' We also save the address (hOldProc) of
    '\\of the previous MessageHandler so we
    ' can reset on StopWindowMessaging>
    hOldProc = SetWindowLongApi(hWindowHandle,_
       GWL_WNDPROC, AddressOf ProcessWindowMessages)

    WindowMessagingInitialised = True
  End Function

  'Function to tear down Message Handling 
  'and return to original Message Handler
  Public Function StopWindowMessaging()
    '\\This statement sets the Message Handling 
    'to be set to the address
    '\\of the previous MessageHandler which 
    'we saved before changing it to ours.
    Call SetWindowLongApi(hWindowHandle, GWL_WNDPROC, hOldProc)
  End Function

  'Function to find VB.NET window and attempt to send message
  Public Function SendMessageToVBNET()
    Dim hwndTarget As Long
    Dim MessageId As Long

    If WindowMessagingInitialised = False Then
      InitWindowMessaging
    End If

    'Get TargetWindow handle from global Window Name
    hwndTarget = VBNET_WindowHandle

    'Get MessageId from API call to RegisterMessage
    MessageId = VB6_TO_DOTNET_MessageId

    'If Window target exists, then PostMessage to target
    If
    hwndTarget <>  0 Then
        Call PostMessage(hwndTarget, MessageId, 0, 0)
    End If
  End Function

  Function to process messages. If not one of our custom messages,
  'then fall through to original Message Handler
  Private Function ProcessWindowMessages(ByVal hwnd As Long, _
    ByVal wMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Integer) As Long

    If wMsg = DOTNET_TO_VB6_MessageId Then
      '\\Respond to the custom message here
      MsgBox "window message received from DOTNET environment"
    Else
      '\\Pass the message to the previous 
      'window procedure to handle it
      ProcessWindowMessages = CallWindowProc(hOldProc, _
                               hwnd, wMsg, wParam, lParam)
    End If
  
  End Function

关注点

我认为此实现非常棒的一点是,它创建了自己的具有用户定义名称的窗口。 因此,您在 VB6 和 VB.NET 中定义了窗口名称的全局常量。 然后,您可以重命名您的应用程序,通信也不会中断。

RegisterWindowMessage API 调用提供了一个系统范围的 MessageId。 对 RegisterWindowMessage 的后续调用将返回相同的 MessageId

VB6:需要注意的一件至关重要的事情是,您需要在应用程序关闭之前断开自定义消息处理程序的连接,否则它会开始在 VB IDE 中处理消息。 跟踪这个问题非常困难,因为当我运行可执行文件时它会很好地工作,但一旦进入 IDE,它就会使 VB 崩溃。 一旦我开始在我的消息处理程序函数中编写 debug.print 语句,一切都变得清晰起来。 不知何故,我没有将消息处理职责交给 MainForm

VB.NET:没什么好注意的。 在 .NET 中比在 VB 中容易多了。 :-)

开发过程中使用的链接

第 3 版现在包含 VB6App2 源代码。 您现在可以使用窗口消息传递

  • VB6 -> VB.NET
  • VB6 -> C#
  • VB6 -> VB6App2
  • VB6App2 -> VB6
  • VB.NET -> VB6
  • VB.NET -> C#
  • C# -> VB6
  • C# -> VB.NET

历史

  1. 首次发布到 The Code Project
  2. 更新了源代码和演示,以包含 C# 项目。
  3. 更新了源代码和演示,以包含 VB6 到 VB6App2。
© . All rights reserved.