fruitloopy
asked on
VB.NET - How to use WTSSendMessage to send messages to users
I am developing an application that members of desktop support use to perform certain support functions. One of these is to send a popup message to a user on the network.
Having found out that sending messages using the msg.exe thats built in to Vista and above is not possible VB.NET in Visual Studio I have learnt that an API call to WTSSENDMESSAGE is what I need.
However, I cannot find any useful code I can use to acheive this, coupled with the fact that I am not a programmer. I just find code that works and change it to my needs.
The best info I could find for this is:
WTSSENDMESSAGE
Can anyone turn this into something useful? I will have to textboxes in the form called:
txtPCName
txtMessage
With a button that sends it:
btnSend
Many thanks
Having found out that sending messages using the msg.exe thats built in to Vista and above is not possible VB.NET in Visual Studio I have learnt that an API call to WTSSENDMESSAGE is what I need.
However, I cannot find any useful code I can use to acheive this, coupled with the fact that I am not a programmer. I just find code that works and change it to my needs.
The best info I could find for this is:
Declare Function WTSSendMessage Lib "wtsapi32.dll" ( _
ByVaL hServer As Long, _
ByVaL SessionId As Long, _
ByVaL pTitle As String, _
ByVaL TitleLength As Long, _
ByVaL pMessage As String, _
ByVaL MessageLength As Long, _
ByVaL Style As Long, _
ByVaL timeout As Long, _
ByRef pResponse As Long, _
ByVaL bWait As Long) As Long
And this link has details and examples in C++WTSSENDMESSAGE
Can anyone turn this into something useful? I will have to textboxes in the form called:
txtPCName
txtMessage
With a button that sends it:
btnSend
Many thanks
ASKER
Thanks TheLearnedOne. I have already read that but I just don't know how to put it into useful code.
I am new to VB.NET.
I am new to VB.NET.
Here is some sample code in VB.NET taken from that p/invoke topic:
Example call:
Dim response As Integer = MessageService.SendMessage ("Hello Kitty", "My name is Bob")
Public Class MessageService
Public Shared Function SendMessage(title As String, message As String, ByRef errorCode As String) As Integer
Dim WTS_CURRENT_SERVER_HANDLE As IntPtr = IntPtr.Zero
Dim WTS_CURRENT_SESSION As Integer = -1
Dim tlen As Integer = title.Length
Dim mlen As Integer = msg.Length
Dim response As Integer = 0
Dim result As Boolean = WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, title, tlen, message, mlen, _
0, 0, resp, False)
Dim err As Integer = Marshal.GetLastWin32Error()
Return response
End Function
End Class
Example call:
Dim response As Integer = MessageService.SendMessage
ASKER
That looks great, thank TheLearnedOne!
It produces an error:
Error 4 Argument not specified for parameter 'errorCode' of 'Public Shared Function SendMessage(title As String, message As String, ByRef errorCode As String) As Integer'.
For this line:
Dim response As Integer = MessageService.SendMessage ("Hello Kitty", "My name is Bob")
Here's my full code
I realise I still may not be calling it correctly but I just cant figure out what's missing.
It produces an error:
Error 4 Argument not specified for parameter 'errorCode' of 'Public Shared Function SendMessage(title As String, message As String, ByRef errorCode As String) As Integer'.
For this line:
Dim response As Integer = MessageService.SendMessage
Here's my full code
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
If Main.Reachable(txtPCName.Text) Then
Dim MyReg As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, txtPCName.Text)
Dim MyRegKey As Microsoft.Win32.RegistryKey
MyRegKey = MyReg.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", True)
MyRegKey.SetValue("PromptOnSecureDesktop", 1, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey = MyReg.OpenSubKey("SYSTEM\CurrentControlSet\Control\Terminal Server", True)
MyRegKey.SetValue("AllowRemoteRPC", 1, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey.Close()
End If
'Dim Message = txtMessage.Text
Dim result = MessageBox.Show("The computer " & txtPCName.Text & " will be sent the message you typed, are you sure you want to do this?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
If result = Windows.Forms.DialogResult.Yes Then
Dim response As Integer = MessageService.SendMessage("Hello Kitty", "My name is Bob")
ElseIf result = Windows.Forms.DialogResult.No Then
Dim MyReg As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, txtPCName.Text)
Dim MyRegKey As Microsoft.Win32.RegistryKey
MyRegKey = MyReg.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", True)
MyRegKey.SetValue("PromptOnSecureDesktop", 0, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey = MyReg.OpenSubKey("SYSTEM\CurrentControlSet\Control\Terminal Server", True)
MyRegKey.SetValue("AllowRemoteRPC", 0, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey.Close()
End If
End Sub
Public Class MessageService
Public Shared Function SendMessage(title As String, message As String, ByRef errorCode As String) As Integer
Dim WTS_CURRENT_SERVER_HANDLE As IntPtr = IntPtr.Zero
Dim WTS_CURRENT_SESSION As Integer = -1
Dim tlen As Integer = title.Length
Dim mlen As Integer = message.Length
Dim response As Integer = 0
Dim result As Boolean = WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, title, tlen, message, mlen, _
0, 0, response, False)
Dim err As Integer = Marshal.GetLastWin32Error()
Return response
End Function
End Class
End Class
I realise I still may not be calling it correctly but I just cant figure out what's missing.
ASKER
I cannot see how I can send this to a remote PC either. Sorry!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
This was all far to complex to implement so I took a different direction. The msg.exe must be run with elevated rights so I used a handy little elevate64.exe file to elevate the msg.exe and then pass commands to it.
First I have to check if the remote registry service is running before changing two required registry values. If the registry values are not changed it will not display the message on the remote PC.
Here's the code if anyone wants to use it:
First I have to check if the remote registry service is running before changing two required registry values. If the registry values are not changed it will not display the message on the remote PC.
Here's the code if anyone wants to use it:
Imports System.Net.NetworkInformation
Imports System.Net
Imports System.Threading
Imports System.Text
Imports System.Diagnostics
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Management
Imports System.ServiceProcess
Public Class Message
Private Sub Message_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
txtPCName.Text = Main.txtHostName.Text()
End Sub
' Is the service running?
' Returns true if we need to start the service
Public Function CheckService(ByVal PC As String) As Boolean
Dim obj As ManagementObject
obj = New ManagementObject("\\" & txtPCName.Text & "\root\cimv2:Win32_Service.Name='RemoteRegistry'")
If Not IsNothing(obj) Then
If obj("StartMode").ToString <> "Disabled" And obj("State").ToString = "Running" Then
Return False
End If
End If
Return True
End Function
Public Sub StartService(ByVal PC As String)
Dim obj As ManagementObject
'Dim inParams, outParams As ManagementBaseObject
'Dim Result As Integer
Dim sc As New ServiceController
obj = New ManagementObject("\\" & txtPCName.Text & "\root\cimv2:Win32_Service.Name='RemoteRegistry'")
' Start the service
If obj("State").ToString <> "Running" Then
' now start the service
sc = New ServiceController("RemoteRegistry", PC)
sc.Start()
sc.WaitForStatus(ServiceControllerStatus.Running)
End If
End Sub
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
If Main.Reachable(txtPCName.Text) Then
CheckService(txtPCName.Text)
If CheckService(txtPCName.Text) = True Then
StartService(txtPCName.Text)
End If
Dim MyReg As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, txtPCName.Text)
Dim MyRegKey As Microsoft.Win32.RegistryKey
MyRegKey = MyReg.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", True)
MyRegKey.SetValue("PromptOnSecureDesktop", 1, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey = MyReg.OpenSubKey("SYSTEM\CurrentControlSet\Control\Terminal Server", True)
MyRegKey.SetValue("AllowRemoteRPC", 1, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey.Close()
End If
Dim result = MessageBox.Show("The computer " & txtPCName.Text & " will be sent the message you typed, are you sure you want to do this?", "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
If result = Windows.Forms.DialogResult.Yes Then
Dim SendMessage As New ProcessStartInfo
SendMessage.WindowStyle = ProcessWindowStyle.Hidden
SendMessage.CreateNoWindow = True
SendMessage.UseShellExecute = False
SendMessage.FileName = """C:\Temp\Elevate64.exe"""
SendMessage.Arguments = " msg.exe /server:" & txtPCName.Text & " /time:0" & " * " & txtMessage.Text
Process.Start(SendMessage)
MsgBox("Your message has been sent")
ElseIf result = Windows.Forms.DialogResult.No Then
Dim MyReg As Microsoft.Win32.RegistryKey = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, txtPCName.Text)
Dim MyRegKey As Microsoft.Win32.RegistryKey
MyRegKey = MyReg.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", True)
MyRegKey.SetValue("PromptOnSecureDesktop", 0, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey = MyReg.OpenSubKey("SYSTEM\CurrentControlSet\Control\Terminal Server", True)
MyRegKey.SetValue("AllowRemoteRPC", 0, Microsoft.Win32.RegistryValueKind.DWord)
MyRegKey.Close()
End If
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
txtMessage.Text = ""
txtMessage.Focus()
End Sub
End Class
wtssendmessage (wtsapi32)
http://www.pinvoke.net/default.aspx/wtsapi32/wtssendmessage.html