ก่อนอื่นมาดูปัญหากันก่อนครับ ว่าทำไมถึงต้องไปไล่ดูว่า มีการ Remote จากเครื่อง User เพื่อมาใช้งาน Application ที่ติดตั้งบนเครื่อง Server หรือป่าว ? เพราะ IT ของลูกค้า อยากรู้ว่ามีใครใช้งานในระบบบ้าง แล้วใช้งานที่เครื่องไหน แต่บังเอิญว่ารอบนี้ ตัว Application ที่พัฒนาถูกไปติดตั้งบนเครื่อง Windows Server พอ User Remote เข้ามาใช้งาน ปรากฏว่าระบบลง Log และ Active User มาจากเครื่อง Serer ที่เป็น Windows Server ทั้งหมดเลยครับ โดยคำสั่ง C# ที่ใช้ดึงว่าเครื่องที่ Run Application อยู่ ชื่อเครื่องอะไร เป็นคำสั่งที่มีใน .NET Framework API ตามตัวอย่าง Code ด้านล่างเลยครับ
String ComputerName = Environment.MachineName;
มาที่โจทยฺ์ใหม่บ้าง เพราะ คำสั่ง Environment.MachineName; มันมีข้อจำกัด ถ้าเอา Application ไปดิดตั้งบน Windows Server มันจะไม่รู้ว่า User Remote มาจากเครื่องไหนครับ คำสั่งนี้จะดึงเฉพาะ แต่ชื่อเครื่อง ของ Server แทน โดยโจทย์ที่ทาง IT ของลูกค้าต้องการ ในกรณีที่มีการ Remote เข้ามาใช้งาน Application มีรูปแบบ ดังนี้ครั
ชื่อเครื่องปลายทาง(ชื่อเครื่องต้นทาง)
หลังจากรู้โจทย์แล้ว มาดูดีกว่าครับ ว่า C# ไม่สิต้องบอกว่า .Net Framework ได้เตรียมอะไรมาช่วยไว้บ้างครับ
- ตัว System.Windows.Forms.SystemInformation.TerminalServerSession เป็นตัวที่บอกว่า Application ที่เขียนขึ่น Run ผ่่าน Remote Desktop หรือป่าวครับ ถ้าใช่ Return True ถ้าไม่ใช่ Return False ครับ
- ตัว Remote Desktop Services API - เอาไว้ช่วยดึงค่าบางอย่าง มาจาก Protocal RDP ครับ
Code ที่ได้ปรับปรุง
- Method GetComputerName() อันนี้เป็น Method ที่เราเปิดให้คนภายนอกใช้นะครับ
public static String GetComputerName() {
String ComputerName;
//ตรวจสอบว่า Session ที่เข้ามา เกิดจากการ Remote หรือป่าว ?
if (System.Windows.Forms.SystemInformation.TerminalServerSession) {
//ถ้ามาจากการ Remote เข้ามา ดึงชื่อเครื่อง โดยมี Pattern
//Pattern >> เครื่องปลายทาง(เครื่องต้นทาง)
//เช่น CHATRI-NGAM(AdminpingNBD)
//Note: เครื่องต้นทาง ดึงจาก GetTerminalServerClientNameWTSAPI() ซึ่งเรียก "Wtsapi32.dll"
ComputerName = Environment.MachineName + "(" + GetTerminalServerClientNameWTSAPI () + ")";
} else {
//ดึงชื่อเครื่องของ Program ที่ Run อยู่
ComputerName = Environment.MachineName;
}
logger.Debug ("Remote Access from " + ComputerName);
return ComputerName;
}- Helper GetTerminalServerClientNameWTSAPI และ WTSQuerySessionInformation เอาไว้ช่วยดึงค่าที่ต้องการจาก RDP Service ครับ
#region Get Remote Machine Name
private static string GetTerminalServerClientNameWTSAPI () {
const int WTS_CURRENT_SERVER_HANDLE = -1;
IntPtr buffer = IntPtr.Zero;
uint bytesReturned;
string strReturnValue = "";
try {
WTSQuerySessionInformation (IntPtr.Zero, WTS_CURRENT_SERVER_HANDLE, WTS_INFO_CLASS.WTSClientName, out buffer, out bytesReturned);
strReturnValue = System.Runtime.InteropServices.Marshal.PtrToStringAnsi (buffer);
} finally {
buffer = IntPtr.Zero;
}
return strReturnValue;
}
[System.Runtime.InteropServices.DllImport ("Wtsapi32.dll")]
private static extern bool WTSQuerySessionInformation (System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);
enum WTS_INFO_CLASS {
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType
}
#endregionผลการทดสอบ
- เมื่อลองเปิด Application ผ่าน Remote Desktop มันแสดงขึ้น ตาม Requirement ที่ตกลงกันไว้ข้างต้น ดังรูป

Reference
- System.Windows.Forms.SystemInformation.TerminalServerSession
- Remote Desktop Services API
- WTSQuerySessionInformation
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.



