Question

I have an Vb.net application made by a third party , that I need to control using outside resources from a simulated environment and must not interact with the desktop. To simulate inputs that a user would normally input from a special screen with specific keys around it, I've built a test control library to control it and send the form image to a .bmp. The form cannot be visible and showed in taskbar , the bmp output will be displayed by the simulated environment.

Using PostMessage and sendKeys work well as long as I don't but ShowInTaskbar = False for the main form. After many read & testing, I have learned enough to try what seems to be the only thing that would work. I've created a form that I setparent using HWND_MESSAGE parameter, this should create a Message-Only Windows, that are supposed to received postMessage, and subclass it's events.msdn.

StackOverflow already about this

Unfortunately , I can't seem to get it to work, and I was hoping someone could tell me what I'm doing wrong.I have been testing several different ways found through out the web about .net , and short of going into message thread peek and feed(maybe(may be)my last hope), they all seem to work until I take the forms out of the taskbar.

Ok, here are the code:

The MsgOnly.vb

Public Class MsgHandling

DllImport("user32.dll", SetLastError:=True,CharSet:=CharSet.Auto)> _ Public Shared Function SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr End Function

Private Shared 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

Part subclassing in the form(Can't show more than what handles the sub classing, privacy issues. Hopefully this will suffice )

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

Test form

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

Not really sure what other details I can provide for now. Anyone as any idea or ways I haven't found?

Thanks for any input

Was it helpful?

Solution

I've found a work around. It seems like the problem comes from the fact that the windows handle is not find with the search functions. I have tried several ways, but since message-only are not enumerated, I can't loop, or at least I wasn't successful.

So I create a file with the handle, that the external program reads and the use that handle to make the PostMessage. This works well for now. I wish I could find a better way, but at least I have something to propose as a solution.

I'm still open to suggestion or other possible workaround:).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top