Originally wrote this up as a reply to a thread where the OP had asked for a way to check to see if the user had used their app for X days... The problem with most approaches is that they use date comparisons. That means the user can get around it by moving the system date back.

Here's something I threw together... it's nothing complicated, still has a loop hole, but for as basic as it is, not too bad. Rather than just storing the install or first-run date, I grab the current date, hash it, and check to see if the hash exists in the settings collection. If not, and we still have "slots" open... then it's considered to be a new date of usage, and the hash gets added to the collection. Once all of the slots have been used, the trial period is over and the function returns false.

Written in VB2008... should work in 2005, and will work in 2010 (although it's only tested in vb2008)

First the setup - From Project properties, go to the settings and create a user scoped setting "UsageDates" Set the type to "Specialized.StringCollection" and leave the default value blank.

Then add these two functions somewhere where your start up form or sub can get to them (like in the form itself, or the module where the Main sub is... where ever)
vb Code:
  1. Private Function CheckDate(ByVal dateToCheck As Date) As Boolean
  2.         'In reality, CheckDate would get the date (current date) itself and not have it passed in
  3.         Dim retValue As Boolean = False 'Fail safe, default to false
  4.         Dim usageDatesLeft As Int16 = 3 ' set it to 4 just for testing
  5.         'Dim usageDatesLeft As Int16 = 30 ' set this to the number of days of application access
  6.  
  7.         'Hash the date
  8.         Dim hashedDate As String = HashDate(dateToCheck)
  9.         'Check to see if the hash value exists in the UsageDates
  10.  
  11.         'Initialize the container if necessary
  12.         If My.Settings.UsageDates Is Nothing Then
  13.             My.Settings.UsageDates = New System.Collections.Specialized.StringCollection
  14.         End If
  15.  
  16.         If My.Settings.UsageDates.Contains(hashedDate) Then
  17.             'then we are ok...  it's already been checked
  18.             retValue = True
  19.             usageDatesLeft -= My.Settings.UsageDates.Count
  20.  
  21.             'sanity check... if the system date is backed up to a previous date in the list, but not the last date
  22.             If usageDatesLeft <= 0 AndAlso My.Settings.UsageDates.IndexOf(hashedDate) <> My.Settings.UsageDates.Count - 1 Then
  23.                 retValue = False
  24.             End If
  25.         Else
  26.             If My.Settings.UsageDates.Count < usageDatesLeft Then
  27.                 My.Settings.UsageDates.Add(hashedDate)
  28.             End If
  29.             usageDatesLeft -= My.Settings.UsageDates.Count
  30.  
  31.  
  32.             'If not, and the remining count has "slots" open, add it
  33.             If usageDatesLeft > 0 Then
  34.                 retValue = True
  35.             Else
  36.                 'If not and tree are no more slots, tell user, exit app
  37.                 retValue = False
  38.             End If
  39.  
  40.         End If
  41.         'Display to the user how many days are remianing:
  42.         MessageBox.Show(String.Format("You have {0} day(s) remaining.", usageDatesLeft))
  43.  
  44.         Return retValue
  45.     End Function
  46.  
  47.     Private Function HashDate(ByVal dateToHash As Date) As String
  48.         'Get a hash object
  49.         Dim hasher As System.Security.Cryptography.MD5 = System.Security.Cryptography.MD5.Create()
  50.         'Take date, make it a Long date and hash it
  51.         Dim data As Byte() = hasher.ComputeHash(System.Text.Encoding.Default.GetBytes(dateToHash.ToLongDateString()))
  52.         ' Create a new Stringbuilder to collect the bytes
  53.         ' and create a string.
  54.         Dim sBuilder As New System.Text.StringBuilder()
  55.  
  56.         ' Loop through each byte of the hashed data
  57.         ' and format each one as a hexadecimal string.
  58.         Dim idx As Integer
  59.         For idx = 0 To data.Length - 1
  60.             sBuilder.Append(data(idx).ToString("x2"))
  61.         Next idx
  62.  
  63.         Return sBuilder.ToString
  64.  
  65.     End Function

To use it, is fairly simple... NOTE: the messageboxes in the CheckDate function were for testing... you could change CheckDate to return the number of days left, or leave it as is...
Here's how I tested it... add a button to a form (strictly for testing... in reality your main sub or the form_load event - or the from constructor - would call checkDate) and add this to the click event:
vb Code:
  1. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  2.         Dim aCount As Integer = 0
  3.         Dim loopIt As Boolean = True
  4.         'My.Settings.Reset() 'This is here for design time support... otherwise you won't get your app to run agin
  5.  
  6.         Do While loopIt
  7.             MessageBox.Show(String.Format("Checking Date: {0}.", Date.Now.AddDays(aCount)))
  8.             loopIt = CheckDate(Date.Now.AddDays(aCount))
  9.             If Not loopIt Then
  10.                 MessageBox.Show("Trial Period Ended! Application closing!")
  11.                 Me.Close()
  12.             Else
  13.                 MessageBox.Show("You can keep using the app")
  14.             End If
  15.             aCount += 1
  16.         Loop
  17.  
  18.     End Sub

Like I said, it's not perfect, I'll provide minimal support for it, in that I'll help you get it going if you want it, but other than that, you're on your own. Ff some one wants to take it and run with it and do something worthwhile with it, or even beef it up some... go right ahead... just let me know, as it would be interesting to see what could be done with it. Or better yet, add the modifications to this thread.

-tg