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






4.79/5 (17投票s)
2004 年 5 月 4 日
2分钟阅读

239857

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
历史
- 首次发布到 The Code Project
- 更新了源代码和演示,以包含 C# 项目。
- 更新了源代码和演示,以包含 VB6 到 VB6App2。