ก่อนอื่นมาดูปัญหากันก่อนครับ ว่าทำไมถึงต้องไปไล่ดูว่า มีการ 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
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.