UP_System_TS.GetClientName PROCEDURE() !,STRING
!orig! ClientName UP_StringClass
ClientName STRING(32) !Max Computer Name is 15
BufferPtr long
BufferLength ULONG
BufferRef &CSTRING
if fpWTSQuerySessionInformation
if upapi_WTSQuerySessionInformation(upapi_WTS_CURRENT_SERVER_HANDLE,upapi_WTS_CURRENT_SESSION,upapi_WTSClientName,BufferPtr,BufferLength) |
and BufferPtr <> 0 | !Check for bad pointer returned
and BufferLength > 1 THEN !Have note from 2010 saw Length of 1 returned that was bad so check > 1 ??
!orig! BufferRef &= new(cstring(BufferLength+1))
!orig! memcpy(address(BufferRef), BufferPtr, BufferLength)
!orig! ClientName.Assign(BufferRef)
!orig! dispose(BufferRef)
BufferRef &= (BufferPtr) &':'& BufferLength !9/4 edit remove " +1 " !<-- &CString &= Address
ClientName = BufferRef
upapi_WTSFreeMemory(BufferPtr)
return CLIP(ClientName) !orig! ClientName.Get()
I can’t find &= (Address)
documented but I’m sure I’ve seen it shown at DevCon by DAB and also by Alexey in comp.lang.
The returned Client Name is defined as a null terminated string. Typically Windows functions that return (or *out) a byte count (string length) do Not include the trailing null; otherwise, an empty string would return 1. I see nothing in the remarks.
I don’t have a WTS server to test with, maybe @Rick_UpperPark can test.
9/4 Edit:
After I replied I was troubled by the parameter being called “Bytes Returned” and not “String Length”. Also the description on MSDN seems clear it’s size not length. Jeff is right the count included the Null byte.
ppBuffer
A pointer to a variable that receives a pointer to the requested information. The format and contents of the data depend on the information class specified in the WTSInfoClass parameter.
pBytesReturned
A pointer to a variable that receives the size, in bytes, of the data returned in ppBuffer .
That doesn’t always mean that there actually IS space allocated beyond that buffer for an extra null. There’s no guarantee what exists beyond the length that you are provided by an API.
I do like the &= technique and use it a lot, but you have to tread carefully with buffers that aren’t your own.
Maybe &STRING could be safer?
Very interesting discussion.
I agree with Jeff, you should not make any assumptions about the memory contents past the buffer length returned by any API.
Additionally, the call to WTSQuerySessionInformation does not just return the address of null terminated strings in BufferRef. It can be the offset of structures like WTSClient, WTSInfo, WTSConfigInfo, etc.
Turns out there is a bug in my original code. The BufferLength returned by the call includes the trailing NULL character. My workstation name is DIMHOLT which is 7 characters. BufferLength is returning 8 when I call to get the client name. No harm in the bug, other than allocating an extra byte of memory for a few milliseconds.
I thought it might be interesting to show how I examined the memory returned by the API call to answer the question of the buffer length and NULL character. Here’s an explanation of the techniques.
Over in this thread, (Using WTSQuerySessionInformation to get client computer name when running in a remote session) a few of us are discussing the use of WTSQuerySessionInformation. This API returns a address that is the offset to the return information. In this case, the return information was a null terminated string (CSTRING) and it was uncertain if the returned buffer length included the NULL character or not.
I fired up the debugger to examine the data and thought it might be interesting …
Rick_UpperPark:
BufferLength is returning 8 when I call to get the client name. No harm in the bug, other than allocating an extra byte of memory for a few milliseconds.
My code ran on 1000’s of systems and worked. I have a note from 2010 that I had one site where the Buffer Size returned was 1. I did not note the String value but I would guess it was CHR(0).
Since Clarion does not allow a CSTRING(1) it would be best for your code to only process the Client Name IF Bytes Returned > 1
.