【问题标题】:Message-Only window not receiving PostMessageMessage-Only 窗口不接收 PostMessage
【发布时间】:2011-05-11 16:23:27
【问题描述】:

我有一个第三方制作的 Vb.net 应用程序,我需要使用来自模拟环境的外部资源进行控制,并且不能与桌面交互。为了模拟用户通常从带有特定键的特殊屏幕输入的输入,我构建了一个测试控件库来控制它并将表单图像发送到 .bmp。表单不可见并显示在任务栏中,bmp输出将由模拟环境显示。

只要我不使用 PostMessage 和 sendKeys 就可以很好地工作,但 ShowInTaskbar = False 对于主窗体。经过多次阅读和测试,我已经学到了足够多的东西来尝试似乎唯一可行的方法。我创建了一个我使用 HWND_MESSAGE 参数设置父级的表单,这应该创建一个仅消息窗口,它应该接收 postMessage,并将其子类化为事件。msdn

StackOverflow already about this

不幸的是,我似乎无法让它工作,我希望有人能告诉我我做错了什么。我已经测试了几种通过网络找到的关于 .net 的不同方法,但缺少进入消息线程偷看和提要(也许(也许是)我最后的希望),它们似乎都可以工作,直到我将表格从任务栏中取出。

好的,代码如下:

MsgOnly.vb

Public Class MsgHandling

DllImport("user32.dll", SetLastError:=True,CharSet:=CharSet.Auto)> _ 公共共享函数 SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As 内部指针 结束函数

私有共享 HWND_MESSAGE As IntPtr = New IntPtr(-3)

Public Event CallBackProc(ByRef m As Message)

Public Sub setParent()
  SetParent(Me.Handle, HWND_MESSAGE)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)

  RaiseEvent CallBackProc(m) 'then RaiseEvent
  MyBase.WndProc(m)
End Sub

End Class

表单中的部分子类化(只能显示处理子类化、隐私问题的内容。希望这就足够了)

Public WithEvents Msg As New MsgHandling

Private Sub XXXXX_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

   '----snips

     Msg.setParent()

   '----snips
end sub


Private Sub CallBackProc(ByRef m As System.Windows.Forms.Message) Handles Msg.CallBackProc

 Me.Text = "Rx events " & m.LParam.ToString() & " " & m.WParam.ToString()

 WndProc(m)

End Sub

测试表格

Public Class Form1

<DllImport("user32.dll")> _
Private Shared Function SetForegroundWindow(ByVal hWnd As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function

Private Shared Function FindWindow( _
     ByVal lpClassName As String, _
     ByVal lpWindowName As String) As IntPtr
End Function
Public Shared Function SetWindowPos( _
ByVal hWnd As IntPtr, _
ByVal hWndInsertAfter As IntPtr, _
ByVal X As Int32, _
ByVal Y As Int32, _
ByVal cy As Int32, _
ByVal uFlags As Int32) _
As Boolean
End Function
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private Declare Function AllowSetForegroundWindow Lib "user32" Alias "AllowSetForegroundWindow" (ByVal dwProcessId As Integer) As Boolean
Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer

Public myProcess As Process = New Process()
Private Const WM_KEYDOWN As Long = 100
Private Const WM_RBUTTONDOWN As Long = 204
Public Shared HWND_MESSAGE As IntPtr = New IntPtr(-3)




Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  myProcess.StartInfo.FileName = "...\XXXXXX.exe" 'Not real name
  myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal
  myProcess.EnableRaisingEvents = True
  AddHandler myProcess.Exited, AddressOf Me.SendKeysTestExited
  myProcess.Start()

End Sub
 Friend Sub SendKeysTestExited(ByVal sender As Object, _
      ByVal e As System.EventArgs)
     Dim myRxProcess As Process = DirectCast(sender, Process)

      myRxProcess.Close()

 End Sub

Private Sub Form1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown

   Dim tHwnd As Long
   Dim rslt As Boolean

   If myProcess.Responding Then      

      tHwnd = FindWindowEx(HWND_MESSAGE, 0, 0, 0)
      PostMessage(HWND_MESSAGE, WM_RBUTTONDOWN, 0, "TEXT TO SEND")

   Else
      myProcess.Kill()
   End If
End Sub


Private Sub Form1_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
    myProcess.Close()
End Sub
End Class

不太确定我现在可以提供哪些其他详细信息。我还没有找到任何想法或方法?

感谢您的任何意见

【问题讨论】:

  • 看到程序员如此频繁地经历这样的痛苦以保持其原始供应商不再支持的旧软件继续运行,这真是非同寻常。无论出于何种原因,通常都是坏的。嗯,商业理念:我敢打赌,首先编写该代码的人仍然存在。可能与离婚的妻子和即将进入大学的 2 1/2 孩子一起从事不同的工作。如果他给你打个电话问他有什么可以帮忙的不是很好吗?据我所知,我可以我的。
  • 实际上,它并不完全是遗留软件,而是更多地采用在正常环境中运行的应用程序接收映射到屏幕周围特殊键的键输入(这是航空电子设置)并在模拟环境中使用它来复制它通常会使用的 I/O。不幸的是,最初的 Dev 无法提供帮助,因为我们正试图以非预期的方式使用他们的软件(拥有这样做的所有权利)。我们还需要进行最小限度的更改,以免在两种设置中真正分支并使用相同的代码,根据环境进行调整。
  • 问题+1,头像+1!去北欧!
  • 感谢 Goldorak84! +1 为 Goldorak 名字 ;)

标签: vb.net winapi winforms-interop .net-3.5


【解决方案1】:

我找到了解决办法。问题似乎来自搜索功能找不到 Windows 句柄的事实。我尝试了几种方法,但由于没有枚举仅消息,我无法循环,或者至少我没有成功。

所以我创建了一个带有句柄的文件,外部程序读取该文件并使用该句柄制作 PostMessage。这目前运作良好。我希望我能找到更好的方法,但至少我有一些建议作为解决方案。

我仍然愿意接受建议或其他可能的解决方法:)。

【讨论】:

  • 因此,对于任何寻求相同解决方案的人来说,我所做的是创建一个 sharedMemory,我在其中编写本机程序读取的句柄。在那里,我还将表单的位图输出字节数组编组到文件映射中。我仍然想知道为什么在创建位图时如果不从磁盘加载文件就无法创建 DIB,创建的任何其他位图都是 DDB。似乎不支持将动态数组编组为结构(应该)
猜你喜欢
  • 2018-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
相关资源
最近更新 更多