Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

VB.NET - How to use WTSSendMessage to send messages to users

Posted on 2014-04-16
8
Medium Priority
?
2,165 Views
Last Modified: 2014-04-30
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:

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

Open in new window

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
0
Comment
Question by:fruitloopy
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
8 Comments
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40005737
This may or may not be helpful:

wtssendmessage (wtsapi32)
http://www.pinvoke.net/default.aspx/wtsapi32/wtssendmessage.html
0
 
LVL 2

Author Comment

by:fruitloopy
ID: 40006035
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.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40006421
Here is some sample code in VB.NET taken from that p/invoke topic:


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 

Open in new window


Example call:
Dim response As Integer = MessageService.SendMessage("Hello Kitty", "My name is Bob")
0
NFR key for Veeam Agent for Linux

Veeam is happy to provide a free NFR license for one year.  It allows for the non‑production use and valid for five workstations and two servers. Veeam Agent for Linux is a simple backup tool for your Linux installations, both on‑premises and in the public cloud.

 
LVL 2

Author Comment

by:fruitloopy
ID: 40006502
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
    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

Open in new window


I realise I still may not be calling it correctly but I just cant figure out what's missing.
0
 
LVL 2

Author Comment

by:fruitloopy
ID: 40006688
I cannot see how I can send this to a remote PC either. Sorry!
0
 
LVL 96

Accepted Solution

by:
Bob Learned earned 1500 total points
ID: 40006951
See what coding in the comment block gets ya ;)

Dim errorCode As String
Dim response As Integer = MessageService.SendMessage("Hello Kitty", "My name is Bob", errorCode)

That code uses current server and session:

Dim WTS_CURRENT_SERVER_HANDLE As IntPtr = IntPtr.Zero
Dim WTS_CURRENT_SESSION As Integer = -1

If you need more information, then that is where it gets trickier.  I believe that you need WTSOpenServer(server name) to get a handle to the server, and WTSEnumerateSessions to get the active sessions on the server.
0
 
LVL 2

Author Comment

by:fruitloopy
ID: 40032134
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:
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

Open in new window

0

Featured Post

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…

618 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question