thongkorn โพสต์ 2020-5-14 12:53:52

[VB.NET] วิธีการสร้างชุดลงทะเบียนโปรแกรม (Registration)

http://www.g2gnet.com/webboard/images/vbnet/registermain.png

สำหรับบทความนี้จะเป็นวิธีการง่ายๆในการทำชุดลงทะเบียนโปรแกรม ซึ่งแอดมินได้สร้างโปรเจค 2 ชุดไว้ในโซลูชั่นเดียวกัน ชุดแรกก็จะเป็นเหมือนกับโปรแกรมให้ลูกค้าใช้งาน อีกส่วนคือการสร้างรหัสลงทะเบียน (เป็นโปรเจคหลัก ต้องเข้าไปเปิด Solution ในโฟลเดอร์ RegisterProgram) เวลานำไปใช้งานจริงเราต้องแยกออกจากกันน่ะครับ ...

ขั้นตอนวิธีการคิดในการเข้ารหัส ...
อ่านซีเรียลนัมเบอร์ของดิสต์ อันนี้เพื่อให้ได้โค้ดง่ายๆเข้าใจไม่ยาก แอดมินให้อ่านซีเรียลนัมเบอร์แบบ Logical Disk หรือ Volume Disk ซึ่งค่านี้จะเปลี่ยนใหม่ทุกครั้งที่มีการฟอร์แมต และที่สำคัญคือสามารถเปลี่ยนค่าได้ ... ดังนั้นในการนำไปใช้งานจริงจึงไม่ปลอดภัย แอดมินแนะนำให้อ่านซีเรียลนัมเบอร์จาก Physical Disk แทน ซึ่งโค้ดในการอ่านก็อยู่ในเว็บบอร์ดแห่งนี้แหละขอรับกระผม

สร้างชุดกุญแจขึ้นมา 1 ชุด

นำ 1 กับ 2 มาทำการเข้ารหัส แน่นอนว่าแอดมินใช้วิธีการเข้ารหัสแบบง่ายๆ ท่านต้องไปศึกษาค้นคว้าเพิ่มเติมเองล่ะกันครับผม

สำหรับชุดโปรแกรมที่ให้ลูกค้า หรือยูสเซอร์ใช้งาน จะต้องทำการอ่านสถานะการลงทะเบียนทุกๆครั้งที่เปิดโปรแกรมขึ้นมา โดยอ่านค่าตัวแรกคือซีเรียลนัมเบอร์ของดิสต์ (ป้องกันการเปลี่ยนแปลงค่าจากผู้ใช้) จากนั้นไปอ่านค่า Product Key หรือรหัสลงทะเบียนที่ได้ทำการ Registry เอาไว้ใน RegEdit หากไม่เจอค่าใดๆ แสดงว่ายังไม่มีการลงทะเบียน ก็ระบุ blnDemo = True หรือยังเป็นชุดทดลองอยู่นั่นเอง แต่หากมีค่า Product Key ก็เอามาทำการเข้ารหัส (เหมือนข้อ 3 ด้านบน) ด้วยซีเรียลนัมเบอร์ฮาร์ดดิสต์กับกุญแจที่กำหนดไว้ แล้วนำมาเปรียบเทียบค่า Product Key ที่ได้ก็เป็นอันจบ ...

การเลือกโปรเจคที่จะให้ทำงานเริ่มต้น (StartUp Project)
http://www.g2gnet.com/webboard/images/vbnet/registerproject.png

การ Registry ค่าต่างๆ การที่แอดมินนำไปไว้ที่ HKEY_CURRENT_USER ก็เพราะว่า Windows 10 มันมีการป้องกันสูง หากนำไปไว้ที่ LOCAL MACHINE มักมีปัญหาในการเขียนค่าลงไป
http://www.g2gnet.com/webboard/images/vbnet/registerregedit.png

มาดูโค้ดในส่วนของการสร้างรหัสลงทะเบียน ... (RegisterProgram) ...Public Class frmGenKeyMaker
    '// เลขชุดเหมือนกุญแจที่ต้องนำมาเข้ารหัสต้องตั้งค่าให้ตรงกัน
    Dim ProgramID As UInt32 = 1234567890

    Private Sub btnGenKey_Click(sender As System.Object, e As System.EventArgs) Handles btnGenKey.Click
      Try
            '// ค่านี้ต้องได้รับมาจากลูกค้า
            Dim ProductNumber As UInt32 = UInt32.Parse(txtProductNumber.Text)
            txtProductKey.Text = Encrypt(ProgramID, ProductNumber)
      Catch ex As Exception
            txtProductKey.Clear()
            MessageBox.Show(ex.Message)
      End Try
    End Sub

    '/ Simple encryption and decryption.
    Private Function Encrypt(ByVal seed As UInt32, ByVal value As UInt32) As UInt32
      Dim rand As New Random(CInt(seed \ 2))
      Return (value Xor CUInt(UInt32.MaxValue * rand.NextDouble()))
    End Function

    Private Sub frmGenKeyMaker_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      txtProductID.Text = ProgramID
      txtProductNumber.Text = GetDriveVolumeSerialNumber()
    End Sub

    Private Function GetDriveVolumeSerialNumber() As String
      Dim DriveSerial As Long
      Dim FSO As Object, Drv As Object
      '/ Create a FileSystemObject object
      FSO = CreateObject("Scripting.FileSystemObject")
      Drv = FSO.GetDrive(FSO.GetDriveName(AppDomain.CurrentDomain.BaseDirectory))
      With Drv
            If .IsReady Then
                DriveSerial = .SerialNumber
            Else    '"Drive Not Ready!"
                DriveSerial = -1
            End If
      End With
      '/ Clean up
      Drv = Nothing
      FSO = Nothing
      GetDriveVolumeSerialNumber = Math.Abs(DriveSerial) 'Hex(Math.Abs(DriveSerial))
    End Function


End Class


มาดูโค้ดในส่วนของผู้ใช้งานในการลงทะเบียน ... (CustomerProgram) ...
Public Class frmCustomerProgram
    '// กำหนดชื่อ Section
    Dim SectionName As String = "SampleProgram"
    '// ตัวอย่างชุดตัวเลขเพื่อทำการเข้ารหัส (เหมือนกุญแจ)
    Dim ProgramID As UInt32 = 1234567890
    '// รหัสลงทะเบียนโปรแกรม
    Dim ProductKey As String
    '// Volume Disk
    Dim ProductNumber As String

    Private Sub frmCustomerProgram_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
      Me.Dispose()
      GC.SuppressFinalize(Me)
      Application.Exit()
    End Sub

    Private Sub frmCustomerProgram_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      Call Register()
    End Sub

    Sub Register()
      '// อ่านค่า Volume Disk ใหม่ เผื่อมีการแก้ไขเปลี่ยนแปลงค่าใน Registry
      ProductNumber = GetDriveVolumeSerialNumber()
      '// อ่านรหัสปลดล็อคโปรแกรมจาก Registry
      ProductKey = ReadAppRegistry(SectionName, "ProductKey", "")
      '// หากไม่มีค่า ProductKey แสดงว่ายังไม่เคยลงทะเบียนโปรแกรม
      If IsNothing(ProductKey) Or Len(ProductKey) = 0 Then
            '// กำหนดให้เป็น DEMO อยู่
            blnDemo = True
            '// กรณีที่เกิดการแก้ไขค่า Volumn Disk ต้องใช้ค่าที่เราอ่านได้เอง
            Call WriteAppRegistry(SectionName, "ProductNumber", ProductNumber)
            '// ไม่มีการลงทะเบียน
            Call WriteAppRegistry(SectionName, "ProductKey", "")
            Me.Text = Application.ProductName & " "
            Exit Sub

            '// แสดงว่ามี ProductKey
      Else
            '// เข้ารหัสค่า ProductKey ที่มาจาก Registry โดยมี ProgramID (กุญแจ)
            Dim ActivateKey As UInt32 = Encrypt(ProgramID, CUInt(ProductNumber))
            '// หากค่าเท่ากัน แสดงว่าลงทะเบียนโปรแกรมถูกต้อง ไม่ต้องทำการเขียนข้อมูลลง Registry
            '/ ---------------------------------------------------------------
            If ActivateKey = ProductKey Then
                blnDemo = False
                Me.Text = Application.ProductName & " "
                '// อาจจะมีการเปลี่ยนแปลงค่าใน Registry ก็เลยทำให้ค่าที่ได้ไม่เท่ากัน
            Else
                blnDemo = True
                '// เขียนข้อมูล Volume Disk กลับลงไปใน Registry อีกครั้ง
                Call WriteAppRegistry(SectionName, "ProductNumber", ProductNumber)
                '// ให้ค่ารหัสลงทะเบียนเป็นค่าว่างเปล่า
                Call WriteAppRegistry(SectionName, "ProductKey", "")
                Me.Text = Application.ProductName & " "
            End If
      End If
    End Sub

    Private Sub btnRegister_Click(sender As System.Object, e As System.EventArgs) Handles btnRegister.Click
      frmRegister.ShowDialog()
    End Sub
End Class
ฟอร์มในการลงทะเบียนโปรแกรม ...
Public Class frmRegister

    '// กำหนดชื่อ Section
    Dim SectionName As String = "SampleProgram"
    '// ตัวอย่างชุดตัวเลขเพื่อทำการเข้ารหัส (เหมือนกุญแจ)
    Dim ProgramID As UInt32 = 1234567890
    '// รหัสลงทะเบียนโปรแกรม
    Dim ProductKey As String
    '// Volume Disk
    Dim ProductNumber As String

    Private Sub frmRegister_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
      Me.Dispose()
      GC.SuppressFinalize(Me)
    End Sub

    Private Sub frmRegister_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      '// อ่านค่า Volume Disk อีกรอบ
      txtProductNumber.Text = GetDriveVolumeSerialNumber()
      '// โหลดค่ารหัสลงทะเบียนมาเก็บไว้
      txtProductKey.Text = ReadAppRegistry(SectionName, "ProductKey", "")
      '// blnDemo จะถูกโหลดตั้งแต่ฟอร์มหลักที่เรียกมา (frmCustomerProgram.vb)
      If Not blnDemo Then
            txtProductKey.Enabled = False
            btnOk.Enabled = False
            btnCancel.Text = "Close"
      End If
    End Sub

    Private Sub btnCancel_Click(sender As System.Object, e As System.EventArgs) Handles btnCancel.Click
      Me.Close()
    End Sub

    Sub Register()
      ProductNumber = txtProductNumber.Text
      '// อ่านค่า ProductKey จาก Registry
      ProductKey = ReadAppRegistry(SectionName, "ProductKey", "")
      '// ยังไม่ได้ลงทะเบียน
      If Len(ProductKey) = 0 And txtProductKey.Text.Trim.Length = 0 Then
            blnDemo = True
            frmCustomerProgram.Text = Application.ProductName & " "
            txtProductKey.Focus()

            '// ตรวจสอบค่าที่ป้อนเข้ามาใน ProductKey
      ElseIf txtProductKey.Text.Trim.Length <> 0 Then
            '// เข้ารหัส ProgramID (กุญแจ) ร่วมกับ ProductNumber (Volume Disk)
            Dim ActivateKey As UInt32 = Encrypt(ProgramID, CUInt(ProductNumber))
            '// เปรียบเทียบค่าที่ได้จากการเข้ารหัสใหม่ (ActivateKey) และค่าที่ผู้ใช้ป้อนเข้ามา
            If ActivateKey = CUInt(txtProductKey.Text) Then
                '// ถูกต้อง ...
                blnDemo = False
                Call WriteAppRegistry(SectionName, "ProductNumber", ProductNumber)
                Call WriteAppRegistry(SectionName, "ProductKey", txtProductKey.Text.Trim)
                MessageBox.Show("Registration Complete.", "Report Status", MessageBoxButtons.OK, MessageBoxIcon.Information)
                frmCustomerProgram.Text = Application.ProductName & " "
                Me.Close()
            Else
                '// ลงทะเบียนมั่ว
                blnDemo = True
                MessageBox.Show("Product Key is not correct.", "Report Status", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                frmCustomerProgram.Text = Application.ProductName & " "
                txtProductKey.Focus()
            End If
      End If
    End Sub

    Private Sub btnOk_Click(sender As System.Object, e As System.EventArgs) Handles btnOk.Click
      Call Register()
    End Sub

End Class
โมดูลในส่วนของฟังค์ชั่นต่างๆ ...
Module modFunction
    '// กำหนดให้เป็นตัวแปรแบบ Public สามารถมองเห็นได้ทั้งโปรเจค
    '// เพื่อระบุว่าเป็นการลงทะเบียนหรือไม่
    '// blnDemo = False ลงทะเบียนเรียบร้อย (ไม่ใช่ชุดทดลอง)
    '// blnDemo = True ยังไม่ได้ลงทะเบียน (ยังเป็นชุดทดลองอยู่)
    Public blnDemo As Boolean = True

    ' / -----------------------------------------------------------------------------------------------
    ' / Registry with VB.NET function
    ' / Function read original font style from Registry and return its.
    Public Function ReadAppRegistry(SectionName As String, _
      KeyName As String, _
      KeyValue As String _
    ) As String

      ' Application Title ...
      Dim AppTitle As String = My.Application.Info.Title
      '// Check exist KeyName, If not have to create new value by default.
      If GetSetting(AppTitle, SectionName, KeyName) = "" Then _
            Call SaveSetting(AppTitle, SectionName, KeyName, KeyValue)

      ' Return Value
      ReadAppRegistry = GetSetting(AppTitle, SectionName, KeyName)

    End Function

    ' / -----------------------------------------------------------------------------------------------
    ' / Save all font style into Registry, No return The use of sub program.
    ' / Registry with VB.NET function
    Public Sub WriteAppRegistry(SectionName As String, _
      KeyName As String, _
      KeyValue As String _
    )
      ' Application Title ...
      Dim AppTitle As String = My.Application.Info.Title
      Call SaveSetting(AppTitle, SectionName, KeyName, KeyValue)
    End Sub

    '/ Simple encryption and decryption.
    Public Function Encrypt(ByVal seed As UInt32, ByVal value As UInt32) As UInt32
      Dim rand As New Random(CInt(seed \ 2))
      Return (value Xor CUInt(UInt32.MaxValue * rand.NextDouble()))
    End Function

    Public Function GetDriveVolumeSerialNumber() As String
      Dim DriveSerial As Long
      Dim FSO As Object, Drv As Object
      '/ Create a FileSystemObject object
      FSO = CreateObject("Scripting.FileSystemObject")
      Drv = FSO.GetDrive(FSO.GetDriveName(AppDomain.CurrentDomain.BaseDirectory))
      With Drv
            If .IsReady Then
                DriveSerial = .SerialNumber
            Else    '"Drive Not Ready!"
                DriveSerial = -1
            End If
      End With
      '/ Clean up
      Drv = Nothing
      FSO = Nothing
      GetDriveVolumeSerialNumber = Math.Abs(DriveSerial) 'Hex(Math.Abs(DriveSerial))
    End Function
End Module
ดาวน์โหลดโค้ดต้นฉบับแบบเต็ม VB.NET (2010) ได้ที่นี่ ...

prawpun โพสต์ 2020-6-8 11:02:33

ขอบคุณคะอาจารย์ ร่ำรวยเงินทองและสุขภาพที่ดีนะคะ

komenservice โพสต์ 2020-9-28 19:58:35

ขอบคุณครับ อาจารย์

0x1souce โพสต์ 2022-3-11 13:07:01

:D:D:Dขอบคุณครับ

0x1souce โพสต์ 2022-3-20 23:18:18

แก้ไขครั้งสุดท้ายโดย 0x1souce เมื่อ 2022-3-21 16:41

สอบถามหน่อยครับ กรณีที่ใส่ เลขมั่ว 7777777777แบบนี้   หลังจากรันแล้ว project error ครับ ต้องแก้ยังไงคับ
แก้ได้แล้วครับ เปลี่ยนจาก CInt เป็น CLng

puklit โพสต์ 2022-10-18 16:44:10

แก้ไขครั้งสุดท้ายโดย puklit เมื่อ 2022-10-22 11:42

ก่อนอื่น ผมต้องขอขอบพระคุณอาจารย์เป็นอย่างสูงที่ได้ถ่ายทอดความรู้ให้แบบฟรี ๆ ไม่มีกั๊ก
สำหรับโปรแกรมด้านล่างนี้ผมได้ศึกษาจากอาจารย์แล้วนำมาต่อยอดในการลงทะเบียนดังนี้ครับ

1. คีย์ Product ID
2. คีย์1
3. คีย2
4. จะเป็น Active LicenseKey ที่ผู้ซื้อโปรแกรมจะต้องส่งข้อมูล Product ID , คีย์1 และ คีย2 กลับมาให้ผู้พัฒนา
    แล้วทางผู้พัฒนาโปรแกรมก็จะส่ง Active LicenseKey กลับไปให้ผู้ซื้อทำการลงทะเบียนต่อไปครับ

รูปตัวอย่าง การลงทะเบียน Active LicenseKey ที่ถูกต้อง


รูปตัวอย่างการลงทะเบียน Active LicenseKey ไม่ถูกต้อง


สำหรับด้านล้างนี้เป็นข้อมูลที่บันทึกการลงทะเบียนโปรแกรมในระบบ Registry ครับ




กรณียังเป็นเวอร์ชั่นทดลองใช้งาน จะแจ้งเตือนวันคงเหลือ ก่อนเข้าสู่หน้าหลัก


กรณีที่หมดวันทดลองใช้งาน ระบบจะแจ้งเตือน ข้อความหลังเข้าสู่ระบบ และจะไม่สามารถเข้าสู่หน้าหลักของโปรแกรมได้


สำหรับรูปด้านล่างนี้เป็นการถอดรหัสจากคีย์ลูกค้า เพื่อสร้าง License key ส่งกลับไปเพื่อให้ลูกค้าลงทะเบียนครับ
(เวอร์ชั่นล่าสุดผมปรับให้เหลือ 2 คีย์ เท่านั้น)





หน้า: [1]
ดูในรูปแบบกติ: [VB.NET] วิธีการสร้างชุดลงทะเบียนโปรแกรม (Registration)