|


Project Properties --> View Windows Settings ...

การนำไปใช้งานจริง ...
โค้ดโปรแกรม VB.NET ในการแก้ปัญหา Network Printer บน Windows 11 Home จะมีอยู่ 2 ขั้นตอนคือ ...
1. สร้าง User Login Credentials เข้าไปเก็บในเครื่อง Windows 11 Home
2. ทำการ Registry ค่า RPC (Remote Procedure Call) ทั้งเครื่องแม่และเครื่องลูก ... กรณีที่เครื่องแม่เป็น Windows 10 ให้รีสตาร์ทใหม่ด้วย
ขั้นตอนการทำงาน: สั่งรันไฟล์ reg-server.reg ที่เครื่องแม่แล้วทำการรีสตาร์ท ส่วนตัวโปรแกรมให้ไปรันที่เครื่องลูก
Registry สำหรับเครื่องแม่ ...
- Windows Registry Editor Version 5.00
- [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print]
- "RpcAuthnLevelPrivacyEnabled"=dword:00000000
คัดลอกไปที่คลิปบอร์ด
Registry สำหรับเครื่องลูก ...
- Windows Registry Editor Version 5.00
- [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Printers\RPC]
- "RpcUseNamedPipeProtocol"=dword:00000001
- "RpcAuthentication"=dword:00000000
- "RpcProtocols"=dword:00000007
- "ForceKerberosForRpc"=dword:00000000
- "RpcTcpPort"=dword:00000000
- [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print]
- "RpcAuthnLevelPrivacyEnabled"=dword:00000000
คัดลอกไปที่คลิปบอร์ด
มาดูโค้ดในส่วนของฟอร์มหลัก ...
- Imports Microsoft.Win32
- Public Class frmMain
- Private Sub btnSave_Click(sender As System.Object, e As System.EventArgs) Handles btnSave.Click
- '// ตรวจสอบค่าว่างของ TextBox Control แต่ละตัว
- Dim RequiredFields As Dictionary(Of TextBox, String) = New Dictionary(Of TextBox, String) From {
- {txtTarget, "Enter your Domain or IP Address."},
- {txtUserName, "Enter your Username."}
- }
- '// ใช้ For Each เพื่อลูปตรวจสอบทุก TextBox ใน Dictionary
- For Each Field In RequiredFields
- If String.IsNullOrWhiteSpace(Field.Key.Text) Then
- MessageBox.Show(Field.Value, "รายงานสถานะ", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
- Field.Key.Focus()
- Return
- End If
- Next
- '//
- If CredentialManager.AddNetworkCredential(txtTarget.Text, txtUserName.Text, txtPassword.Text) Then
- MessageBox.Show("เพิ่ม Network Credential สำเร็จ", "รายงานสถานะ", MessageBoxButtons.OK, MessageBoxIcon.Information)
- '// เรียกไปโปรแกรมย่อยในการเขียนข้อมูลลง Registry
- Call RegistryRPC()
- End If
- End Sub
- ' / --------------------------------------------------------------------------------------
- ' / Registry RPC (Remote Procedure Call)
- ' / --------------------------------------------------------------------------------------
- Private Sub RegistryRPC()
- Try
- Dim RegPath As String = "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Printers\RPC"
- '// การกำหนดค่าให้กับ Key
- '// ค่า 1 (เปิด) ใช้ Named Pipes เป็นโปรโตคอล RPC
- Registry.SetValue(RegPath, "RpcUseNamedPipeProtocol", 1, RegistryValueKind.DWord)
- '// ระบุวิธีการรับรองตัวตนของ RPC, 0 = ไม่มีการตรวจสอบสิทธิ์ (ไม่ปลอดภัย)
- Registry.SetValue(RegPath, "RpcAuthentication", 0, RegistryValueKind.DWord)
- '// ระบุว่าจะเปิดใช้งานโปรโตคอล RPC อะไรบ้าง (1 = TCP/IP, 2 = Named Pipes, 4 = LRPC (Local RPC), 7 = ทั้งหมด (1+2+4))
- Registry.SetValue(RegPath, "RpcProtocols", 7, RegistryValueKind.DWord)
- '// ค่า 1 จะบังคับใช้เฉพาะ Kerberos เท่านั้น, ค่า 0 = ไม่บังคับ
- Registry.SetValue(RegPath, "ForceKerberosForRpc", 0, RegistryValueKind.DWord)
- '// ใช้กำหนด TCP Port แบบคงที่ สำหรับ RPC, ค่า 0 หมายถึง ปล่อยให้ระบบกำหนดพอร์ตอัตโนมัติ
- Registry.SetValue(RegPath, "RpcTcpPort", 0, RegistryValueKind.DWord)
- '// Registry สำหรับ RpcAuthnLevelPrivacyEnabled
- '// 0 ปิดการเข้ารหัส (Privacy Disabled), 1 เปิดใช้งานการเข้ารหัส (Privacy Enabled)
- RegPath = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print"
- Registry.SetValue(RegPath, "RpcAuthnLevelPrivacyEnabled", 0, RegistryValueKind.DWord)
- MessageBox.Show("นโยบาย RPC ถูกกำหนดเรียบร้อย", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information)
- Catch ex As Exception
- MessageBox.Show("เกิดข้อผิดพลาด: " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
- End Try
- End Sub
- Private Sub txtTarget_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtTarget.KeyPress
- If Asc(e.KeyChar) = Keys.Enter Then
- e.Handled = True
- SendKeys.Send("{TAB}")
- End If
- End Sub
- Private Sub txtUserName_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtUserName.KeyPress
- If Asc(e.KeyChar) = Keys.Enter Then
- e.Handled = True
- SendKeys.Send("{TAB}")
- End If
- End Sub
- Private Sub txtPassword_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtPassword.KeyPress
- If Asc(e.KeyChar) = Keys.Enter Then
- e.Handled = True
- SendKeys.Send("{TAB}")
- End If
- End Sub
- Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
- txtTarget.Text = ""
- txtUserName.Text = ""
- txtPassword.Text = ""
- End Sub
- Private Sub btnExit_Click(sender As System.Object, e As System.EventArgs) Handles btnExit.Click
- Me.Close()
- End Sub
- Private Sub frmMain_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
- Me.Dispose()
- GC.SuppressFinalize(Me)
- Application.Exit()
- End Sub
- End Class
คัดลอกไปที่คลิปบอร์ด
คลาสสำหรับการสร้าง User Login Credentials ...
- Imports System.Net.NetworkInformation
- Imports System.Runtime.InteropServices
- Imports System.Text
- Imports System.IO
- Public Class CredentialManager
- <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
- Public Structure CREDENTIAL
- Public Flags As UInteger
- Public Type As UInteger
- Public TargetName As String
- Public Comment As String
- Public LastWritten As Long
- Public CredentialBlobSize As UInteger
- Public CredentialBlob As IntPtr
- Public Persist As UInteger
- Public AttributeCount As UInteger
- Public Attributes As IntPtr
- Public TargetAlias As String
- Public UserName As String
- End Structure
- <DllImport("advapi32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
- Public Shared Function CredWrite(ByRef credential As CREDENTIAL, ByVal flags As UInteger) As Boolean
- End Function
- ' / --------------------------------------------------------------------------------------
- ' / ส่วนของการเพิ่ม Target, Username และ Password เข้าไปใน Credential Manager ของ Windows 11 Home
- ' / --------------------------------------------------------------------------------------
- Public Shared Function AddNetworkCredential(target As String, username As String, password As String) As Boolean
- Cursor.Current = Cursors.WaitCursor
- Try
- '// ตรวจสอบการ ping ไปยังเป้าหมาย
- If Not PingHost(target) Then
- MessageBox.Show("ไม่สามารถเชื่อมต่อกับ: " & target, "การตรวจสอบล้มเหลว", MessageBoxButtons.OK, MessageBoxIcon.Warning)
- Return False
- End If
- Finally
- Cursor.Current = Cursors.Default
- End Try
- '// แปลงรหัสผ่านจาก String เป็นอาร์เรย์ของ Byte ด้วยการเข้ารหัสแบบ Unicode
- Dim PasswordBytes As Byte() = Encoding.Unicode.GetBytes(password)
- '// จองพื้นที่ในหน่วยความจำแบบ unmanaged เพื่อใช้เก็บ byte array ของ Password
- Dim PasswordPtr As IntPtr = Marshal.AllocCoTaskMem(PasswordBytes.Length)
- Marshal.Copy(PasswordBytes, 0, PasswordPtr, PasswordBytes.Length)
- '// Type เช่น 2 = CRED_TYPE_DOMAIN_PASSWORD
- '// Target เช่น 192.168.1.11 หรือ thongkorn-pc
- '// UserName เช่น admin หรือ everyone
- '// Persist เช่น 2 = CRED_PERSIST_LOCAL_MACHINE
- Dim cred As New CREDENTIAL With {
- .Type = 2,
- .TargetName = target,
- .UserName = username,
- .CredentialBlobSize = CUInt(PasswordBytes.Length),
- .CredentialBlob = PasswordPtr,
- .Persist = 2
- }
- '// เรียกใช้ ฟังก์ชัน Win32 API CredWrite (มาจาก advapi32.dll) ซึ่งใช้เพื่อบันทึกข้อมูล Credential (ชื่อผู้ใช้และรหัสผ่าน) ลงใน Windows Credential Manager
- Dim result = CredWrite(cred, 0)
- '// คืนพื้นที่หน่วยความจำแบบ unmanaged ที่จองไว้ก่อนหน้านี้ด้วย Marshal.AllocCoTaskMem
- Marshal.FreeCoTaskMem(PasswordPtr)
- If Not result Then MessageBox.Show("การเพิ่ม Network Credential ล้มเหลว: " & Marshal.GetLastWin32Error(), "รายงานสถานะ", MessageBoxButtons.OK, MessageBoxIcon.Error)
- Return result
- End Function
- '// ตรวจสอบว่าเป้าหมายสามารถ ping ได้หรือไม่
- Public Shared Function PingHost(host As String) As Boolean
- Try
- Using ping As New Ping()
- Dim reply = ping.Send(host, 1000) '// Timeout = 1 วินาที
- Return reply.Status = IPStatus.Success
- End Using
- Catch
- Return False
- End Try
- End Function
- End Class
คัดลอกไปที่คลิปบอร์ด
ดาวน์โหลดโค้ดต้นฉบับ VB.NET (2010) ได้ที่นี่ ...
|
ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง
คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน
x
|