If you want to send a message to your computer, call WTSOpenServer with the name of your computer (returned from GetComputerName)
WTSSendMessageA handle?
Hi All,
Windows 11-pro 22H2
https://learn.microsoft.com/en-us/windows/win32/api/wtsapi32/nf-wtsapi32-wtssendmessagea
WTSSendMessageA states:
[in] hServer
A handle to an RD Session Host server. Specify a handle opened by the WTSOpenServer function, or specify WTS_CURRENT_SERVER_HANDLE to indicate the RD Session Host server on which your application is running.
If I choose NOT to use "WTS_CURRENT_SERVER_HANDLE", how to I get my "handle to an RD Session Host server"?
Many thanks,
-T
Windows API - Win32
-
Jeanine Zhang-MSFT 5,981 Reputation points • Microsoft Vendor
2022-11-25T09:01:48.37+00:00 Have you solved your issue? Have you got any updates about this issue?
-
Todd Chester 636 Reputation points
2022-11-26T23:32:07.977+00:00 Still working on it.
Sign in to comment
2 answers
Sort by: Most helpful
-
Castorix31 71,866 Reputation points
2022-11-19T08:26:26.257+00:00 -
Todd Chester 636 Reputation points
2022-11-19T08:39:29.007+00:00 Thank you for your response. Do you know the answer to the question I actually asked?
-
Castorix31 71,866 Reputation points
2022-11-19T08:50:46.17+00:00 As I said, you just call WTSOpenServer with your computer name, which is the same thing as WTS_CURRENT_SERVER_HANDLE,
or with a server name where the message will be sent... -
Todd Chester 636 Reputation points
2022-11-19T09:00:51.33+00:00 Thank you! And sorry for the misunderstanding.
Is theer a call to get my ;local computer's server's name?
-
Todd Chester 636 Reputation points
2022-11-19T09:11:26.73+00:00 Which one of these is the correct format for my local computer's server name?
set | grep -i kvm
COMPUTERNAME=KVM-W11
LOGONSERVER=\KVM-W11
USERDOMAIN=KVM-W11
USERDOMAIN_ROAMINGPROFILE=KVM-W11 -
Castorix31 71,866 Reputation points
2022-11-19T09:49:24.2+00:00 Various info from local computer can be got with GetComputerNameEx
-
RLWA32 32,156 Reputation points
2022-11-19T10:00:28.81+00:00 ...the name of your computer (returned from GetComputerName)
@Castorix31 previously advised the function to use to get your computer's name as shown above.
-
Todd Chester 636 Reputation points
2022-11-20T08:50:59.37+00:00 What is the close handle command?
Also
C++
HANDLE WTSOpenServerA(
[in] LPSTR pServerName
);I am getting back "2762949296". Perhaps it the pointer (memory address) of the pointer instead of the pointer itself?
Using that value in hServer
C++
BOOL WTSSendMessageA(
[in] HANDLE hServer,
[in] DWORD SessionId,
[in] LPSTR pTitle,
[in] DWORD TitleLength,
[in] LPSTR pMessage,
[in] DWORD MessageLength,
[in] DWORD Style,
[in] DWORD Timeout,
[out] DWORD *pResponse,
[in] BOOL bWait
);Exits my program.
-
RLWA32 32,156 Reputation points
2022-11-20T09:30:37.49+00:00 You will be pleased at how many of your questions can be answered by carefully and completely reading the documentation for the Windows API functions that you call. For example, the Remarks section in the documentation for WTSOpenServerA includes -
"If the function fails, it returns a handle that is not valid. You can test the validity of the handle by using it in another function call."
and also
"When you have finished using the handle returned by WTSOpenServer, release it by calling the WTSCloseServer function.
You do not need to open a handle for operations performed on the RD Session Host server on which your application is running. Use the constant WTS_CURRENT_SERVER_HANDLE instead."
It seems to me that simply using WTS_CURRENT_SERVER_HANDLE should considerably simplify things. If your call to WTSSendMessageA fails when using WTS_CURRENT_SERVER_HANDLE then you are probably passing some other invalid parameter to the function.
-
Todd Chester 636 Reputation points
2022-11-20T09:36:44.557+00:00 WTS_CURRENT_SERVER_HANDLE works when called from the command line, but not from Task Scheduler as administrator, so I was trying to get the call a handle it could use.
You have any ideas?
-
RLWA32 32,156 Reputation points
2022-11-20T09:40:45.597+00:00 In my response to this problem in your earlier thread in which you indicated that WTSSendMessage failed with an access denied error code I advised that a possible cause was passing the wrong session id to the function.
-
RLWA32 32,156 Reputation points
2022-11-20T10:05:39.16+00:00 Results from quick test passing valid and invalid session ids -
-
Todd Chester 636 Reputation points
2022-11-20T10:10:19.563+00:00 C++ DWORD GetCurrentProcessId();
C++
BOOL ProcessIdToSessionId(
[in] DWORD dwProcessId,
[out] DWORD *pSessionIdUsed together are returning a "1". Same as the dll you sent me
-
RLWA32 32,156 Reputation points
2022-11-20T10:14:34.803+00:00 Please reread my previous comments.
I already told you that if you use that code from session 0 it will return 0 as the session id and that you needed to use WTSEnumerateSessions.
That's the reason why I helped you by writing the DLL!!
Looks like we've gone full circle.
-
RLWA32 32,156 Reputation points
2022-11-20T10:19:20.213+00:00 To refresh your memory -
-
Todd Chester 636 Reputation points
2022-11-20T10:30:46.967+00:00 I said it was return a 1, just like yours. Where did you get the 0 from?
I am trying to figure out why your works and mine does not. Would printing out every singe [in] value help you?
-
RLWA32 32,156 Reputation points
2022-11-20T10:41:06.45+00:00 When called from a process running in session 0 the function exported from the dll uses WTSEnumerateSessions to identify the active session and obtain its id. It then modifies the title string to append thé active session id and passes that id to WTSSendMessage.
Apparently, your code is passing a session id of 0 to WTSSendMessage when it is run by the task scheduler.
-
Todd Chester 636 Reputation points
2022-11-20T11:00:21.847+00:00 WTSSendMessageX:
Handle = <0>
SessionId = <1>
pTitle = <80 111 112 85 112 84 101 115 116 46 112 108 54 0>
TitleLength = <13>
pMessage =<77 121 32 111 119 110 32 110 97 116 105 118 101 32 99 97 108 108 0>
MessageLength = <18>
Style = <64>
Timeout = <5
bWait =<1> -
RLWA32 32,156 Reputation points
2022-11-20T11:08:33.567+00:00 None of the above means anything without giving us the context. Where are you getting the session ID from? Are you running this from the command line or from task scheduler?
-
Todd Chester 636 Reputation points
2022-11-20T11:16:15.12+00:00 That was a debug written right before my call from Task Scheduler.
I am not sure handle = 0 is correct.
Session ID = 1 (I hard coded it this time) -
RLWA32 32,156 Reputation points
2022-11-20T11:40:32.17+00:00 A handle value of 0 should be OK. What is the source of the sessionid value of 1?
If you hard code the correct session id in your code and it runs successfully when executed from the command line then it should also succeed when run by the task scheduler.
-
Todd Chester 636 Reputation points
2022-11-20T11:50:48+00:00 my DWORD $SessionId = GetSessionId;
comes from
sub GetCurrentProcessId()
is native("Kernel32")
is symbol("GetCurrentProcessId")
returns DWORD
{ * };sub GetProcessId() {
my Int $Id = -2300;
$Id = GetCurrentProcessId.Int;
print "ProcessId\t= <" ~ $Id ~ "> from Kernel32\n";
return $Id;
}sub ProcessIdToSessionId(
DWORD $dwProcessId,
DWORD $pSessionId is rw
)
is native("Kernel32")
is symbol("ProcessIdToSessionId")
returns Bool # note: C++ type Bool is actually a DWORD
{ * };sub GetSessionId() {
my DWORD $Id = -2300;
my DWORD $Session = -2300;
my DWORD $RtnBool = -2300; # C++ BOOL is actually DWORD
my Bool $Error = False;$Id = GetProcessId;
$RtnBool = ProcessIdToSessionId $Id, $Session;
$Error = $RtnBool.Bool.not; # $RtnBool: 0=ture; 1=falseProcessIdToSessionId $Id, $Session;
print "Session\t\t= <" ~ $Session ~ "> fron Kernel32\n";
if $Error { print "GetSessionId ProcessIdToSessionId returned an error\n"; }
return $Session.Int;
} -
RLWA32 32,156 Reputation points
2022-11-20T11:59:02.747+00:00 Sorry, I can't decipher your posted code but I understand what you are trying to accomplish.
If it returns the same session id from the command line as the "query session" command then it is correct.
So what happens when your code uses the correct hard coded session id for calling WTSSendMessageA when run from the command line?
-
Todd Chester 636 Reputation points
2022-11-20T12:06:09.793+00:00 everything works from the command line. My problem is gettig it to run as administrator from Task Scheduler.
And now I did something that the task scheduler says running forever. I have to fix that before continuing, And I am calling it a night.
-
Todd Chester 636 Reputation points
2022-11-20T12:15:05.34+00:00 I just reproduced the access is denied from an administrator command shell. This is going to get interesting (tomorrow)!
-
Todd Chester 636 Reputation points
2022-11-20T21:36:50.943+00:00 Okay, it is tomorrow and I can finally operate as administrator off a network drive.
C++
HANDLE WTSOpenServerA(
[in] LPSTR pServerName
);is returning
Handle = <4054587520>
And my program dies without an error when I call WTSSendMessage with that handle. Should I be using "gethostname" instead?
-
RLWA32 32,156 Reputation points
2022-11-20T21:43:25.8+00:00 Can you successfully use the dll in the same circumstances?
-
Todd Chester 636 Reputation points
2022-11-20T21:57:53.12+00:00 Yes, but only from a command prompt. HANDLE WTSOpenServerA is returning me a bizarre handle. I am wondering if it is a pointer to a memory address I am getting back?
Nothing is working in the Task Scheduler at the moment
-
RLWA32 32,156 Reputation points
2022-11-20T21:59:43.767+00:00 What? Are you now saying that the dll function that I wrote no longer works properly from the task scheduler?
-
Todd Chester 636 Reputation points
2022-11-20T22:32:36.7+00:00 The DLL is working in the Task Scheduler again. I had to move the program out of a network drive and put it in C:
Here is the latest
"GetSessionId" returns <1> in a shell and it works.
"GetSessionId" returns <0> run from the task scheduler DOES NOT work. (But we knew that would happen.)If I hard code
my DWORD $SessionId = 1;
My stuff works in both places.If I hard code
my DWORD $SessionId = WTS_CURRENT_SESSION;
$SessionId = <4294967295>
And it works in the shell but not the tack schedulerI am thinking that since WTS_CURRENT_SESSION is "-1" and $SessiodID is a Cardinal (unsigned integer), 4294967295 is actually "-1".
Changing $SessionId's type to "Int" (integer) gets me back my "-1" back". Works in the shell, but not in Task Scheduler.
So the 64,0000 question is "how do I get
"GetSessionId"
to return "1" when I am running from Task Scheduler? -
Todd Chester 636 Reputation points
2022-11-20T22:39:15.143+00:00 I> What? Are you now saying that the dll function that I wrote no longer works properly from the test scheduler?
Your dll works fine everywhere. But I have to run it from the C: drive to get it to work with the task scheduler.
My "GetSessionId" is returning "0" when I am running from Task Schedule. That is the remaining issue.
Sign in to comment -
-
RLWA32 32,156 Reputation points
2022-11-20T22:40:18.553+00:00 We've been through this several times already. Your Raku function will never work properly from the task scheduler which runs a process in session 0 until it uses WTSEnumerateSessions.
-
Todd Chester 636 Reputation points
2022-11-20T22:57:45.71+00:00 I was not looking forward to that, but I think I hve to now. Thank you!
-
Todd Chester 636 Reputation points
2022-11-26T23:30:42.573+00:00 I am still working on it.
Sign in to comment -