Visual Basic Locale/Regionalization Routines

SetLocaleInfo: Change System Long and Short Date Formats
     
Posted:   Sunday August 8, 1999
Updated:   Monday December 26, 2011
     
Applies to:   VB5, VB6
Developed with:   VB6, Windows NT4
OS restrictions:   None
Author:   VBnet - Randy Birch
     

Related:  

SetLocaleInfo: Change System Long and Short Date Formats
WM_TIMECHANGE: Detect System Changes to the Date/Time
EnumDateFormats: Regional Locale Date Settings
EnumTimeFormats: Regional Locale Time Settings
GetLocaleInfo: Regional Locale Date Settings
       
 Prerequisites
VB5 or VB6.

Thus far we've seen how to enumerate Locale information (date and time formats, separators etc), Calendar information (days and months, both full and abbreviated), as well as retrieve date formats, the calendar type and assorted other national language settings controlled through Windows' Regional Settings dialog.

A need may arise where an application requires that a specific long or short date format be implemented on the target machine. Applications for the public should never change a registry preference; it is always preferable to inform the user the current settings will cause difficulties and ask them to manually make the required change.

But in-house applications targeting the corporate environment are an entirely different matter. In the corporate environment, computer management is the domain of the IT department, not the user. Given the mission-critical nature of business applications, the systems office is justified in dictating how a machine's long and short date are to be configured and as such any mechanism to test and revert to the correct system settings is warranted.

Therefore, with this understanding, here is how to both retrieve and set the users short and long date formats to an application-defined string. This method also provides for changing the short date separator - for example if the separator is a slash - yyyy/mm/dd - and the IT department designates dates should use dashes - yyyy-mm-dd - setting the new short date will also change the default separator.

In order demo only the most significant code required for this functionality the code allows the entering of and string as the new long or short date format. In practice, you'll want to add significant error checking to assure that only valid characters are entered.

SetLocaleInfo only provides for changing of a subset of available locale settings, as outlined below. The two bolded items are those used in this demo.

The following LCTYPE values are valid for this function:

LOCALE_ICALENDARTYPE LOCALE_SDATE
LOCALE_ICURRDIGITS LOCALE_SDECIMAL
LOCALE_ICURRENCY LOCALE_SGROUPING
LOCALE_IDIGITS LOCALE_SLIST
LOCALE_IFIRSTDAYOFWEEK LOCALE_SLONGDATE
LOCALE_IFIRSTWEEKOFYEAR LOCALE_SMONDECIMALSEP
LOCALE_ILZERO LOCALE_SMONGROUPING
LOCALE_IMEASURE LOCALE_SMONTHOUSANDSEP
LOCALE_INEGCURR LOCALE_SNEGATIVESIGN
LOCALE_INEGNUMBER LOCALE_SPOSITIVESIGN
LOCALE_IPAPERSIZE LOCALE_SSHORTDATE
LOCALE_ITIME LOCALE_STHOUSAND
LOCALE_S1159 LOCALE_STIME
LOCALE_S2359 LOCALE_STIMEFORMAT
LOCALE_SCURRENCY LOCALE_SYEARMONTH
 BAS Module Code
Place the following code into the general declarations area of a bas module:

Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public thisCombo As ComboBox

Public Const LOCALE_SLANGUAGE As Long = &H2     'localized name of language
Public Const LOCALE_SSHORTDATE As Long = &H1F   'short date format string
Public Const LOCALE_SLONGDATE As Long = &H20    'long date format string
Public Const DATE_LONGDATE As Long = &H2
Public Const DATE_SHORTDATE As Long = &H1
Public Const HWND_BROADCAST As Long = &HFFFF&
Public Const WM_SETTINGCHANGE As Long = &H1A

Public Declare Function PostMessage Lib "user32" _
   Alias "PostMessageA" _
  (ByVal hwnd As Long, _
   ByVal wMsg As Long, _
   ByVal wParam As Long, _
   lParam As Any) As Long

Public Declare Function EnumDateFormats Lib "kernel32" _
   Alias "EnumDateFormatsA" _
  (ByVal lpDateFmtEnumProc As Long, _
   ByVal Locale As Long, _
   ByVal dwFlags As Long) As Long

Public Declare Sub CopyMemory Lib "kernel32" _
   Alias "RtlMoveMemory" _
  (Destination As Any, _
   Source As Any, _
   ByVal Length As Long)

Public Declare Function GetSystemDefaultLCID Lib "kernel32" () As Long

Public Declare Function GetLocaleInfo Lib "kernel32" _
   Alias "GetLocaleInfoA" _
  (ByVal Locale As Long, _
   ByVal LCType As Long, _
   ByVal lpLCData As String, _
   ByVal cchData As Long) As Long

Public Declare Function SetLocaleInfo Lib "kernel32" _
    Alias "SetLocaleInfoA" _
   (ByVal Locale As Long, _
    ByVal LCType As Long, _
    ByVal lpLCData As String) As Long


Public Function GetUserLocaleInfo(ByVal dwLocaleID As Long, _
                                  ByVal dwLCType As Long) As String

   Dim sReturn As String
   Dim r As Long

  'call the function passing the Locale type
  'variable to retrieve the required size of
  'the string buffer needed
   r = GetLocaleInfo(dwLocaleID, dwLCType, sReturn, Len(sReturn))
    
  'if successful..
   If r Then
    
     'pad the buffer with spaces
      sReturn = Space$(r)
       
     'and call again passing the buffer
      r = GetLocaleInfo(dwLocaleID, dwLCType, sReturn, Len(sReturn))
     
     'if successful (r > 0)
      If r Then
      
        'r holds the size of the string
        'including the terminating null
         GetUserLocaleInfo = Left$(sReturn, r - 1)
      
      End If
   
   End If
    
End Function


Public Function EnumCalendarDateProc(lpDateFormatString As Long) As Long

  'application-defined callback function for EnumDateFormats
  
  'populates combo assigned to global var thisCombo
   thisCombo.AddItem StringFromPointer(lpDateFormatString)
   
  'return 1 to continue enumeration
   EnumCalendarDateProc = 1
   
End Function


Private Function StringFromPointer(lpString As Long) As String

   Dim pos As Long
   Dim buffer As String
   
  'pad a string to hold the data
   buffer = Space$(128)
   
  'copy the string pointed to by the return value
   CopyMemory ByVal buffer, lpString, ByVal Len(buffer)
   
  'remove the trailing null and trim
   pos = InStr(buffer, Chr$(0))
   
   If pos Then
      StringFromPointer = Left$(buffer, pos - 1)
   End If

End Function
 Form Code
Create a form containing two frames. Into Frame1 (Long Date Info), place Combo1, Label1, Text1 and Command1.  Into Frame2 place Combo2, Label2, Text2 and Command2.

Add two more command button (Command3 & 4) another text box (Text3), and the following code:


Option Explicit


Private Sub Form_Load()

   Command1.Enabled = Combo1.ListIndex > -1
   Command2.Enabled = Combo2.ListIndex > -1
   
   Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
   
End Sub


Private Sub Command1_Click()

   Dim LCID As Long
   Dim sNewFormat As String
   
   LCID = GetSystemDefaultLCID()
   
   sNewFormat = Combo1.Text
   
   If Len(sNewFormat) > 0 Then
   
     'set the new long date format
      Call SetLocaleInfo(LCID, LOCALE_SLONGDATE, sNewFormat)
      
     'send a system notification message that a change was made
      Call PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0&, ByVal 0&)
      
     'update the textbox
      Text1.Text = GetUserLocaleInfo(LCID, LOCALE_SLONGDATE)
      
     'assign the target combo box control and clear
      Set thisCombo = Form1.Combo1
      thisCombo.Clear
       
     'enumerate new long date formats
      Call EnumDateFormats(AddressOf EnumCalendarDateProc, LCID, DATE_LONGDATE)
   
   End If
   
End Sub


Private Sub Command2_Click()

   Dim LCID As Long
   Dim sNewFormat As String
   
   LCID = GetSystemDefaultLCID()
   
   sNewFormat = Combo2.Text
   
   If Len(sNewFormat) > 0 Then
   
     'set the new long date format
      Call SetLocaleInfo(LCID, LOCALE_SSHORTDATE, sNewFormat)

     'send a system notification message that a change was made
      Call PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0&, ByVal 0&)
            
     'update the textbox and label
      Text2.Text = GetUserLocaleInfo(LCID, LOCALE_SSHORTDATE)
   
     'assign the target combo box control
      Set thisCombo = Form1.Combo2
      thisCombo.Clear
       
     'enumerate new long date formats
      Call EnumDateFormats(AddressOf EnumCalendarDateProc, LCID, DATE_SHORTDATE)
   
   End If
   
End Sub


Private Sub Command3_Click()

 'open the control panel Regional Date Settings 
  Call Shell("rundll32.exe shell32.dll,Control_RunDLL intl.cpl,,4", vbNormalFocus)
   
End Sub


Private Sub Command4_Click()

   Dim LCID As Long
   
   LCID = GetSystemDefaultLCID()
   
  'show localized name of language
   Text3.Text = GetUserLocaleInfo(LCID, LOCALE_SLANGUAGE)
   
  '-------------------------
  'assign the target combo box control
   Set thisCombo = Form1.Combo1
  
  'enumerate available long date formats
   Call EnumDateFormats(AddressOf EnumCalendarDateProc, LCID, DATE_LONGDATE)
   
  'Show the user's Long date format string
   Text1.Text = GetUserLocaleInfo(LCID, LOCALE_SLONGDATE)
   
  '-------------------------
  'assign the target combo box control
   Set thisCombo = Form1.Combo2
   
  'enumerate available short date formats
   Call EnumDateFormats(AddressOf EnumCalendarDateProc, LCID, DATE_SHORTDATE)
   
  'Show the user's Short date format string
   Text2.Text = GetUserLocaleInfo(LCID, LOCALE_SSHORTDATE)

End Sub


Private Sub Text1_Change()

   Label1.Caption = Format$(Date, Text1.Text)

End Sub


Private Sub Text2_Change()

   Label2.Caption = Format$(Date, Text2.Text)
   
End Sub

Private Sub Combo1_Click()

   Command1.Enabled = Combo1.ListIndex > -1
   
End Sub


Private Sub Combo2_Click()

   Command2.Enabled = Combo2.ListIndex > -1
   
End Sub
 Comments
Save the program and run. The values displayed should correspond to the date strings for your system. Select an alternate long or short date string, or create a new one and press Apply. Regional Settings are changed to reflect your new selection. Note that the control panel (on NT4 anyway) doesn't respond to the broadcast message posted - you'll need to close and reopen it to see the effected change.
While the GetSystemDefaultLCID function retrieves the system default locale identifier, this is often inappropriate or insufficient in a networked environment or under an operating system where multiple locales have been installed. For example, it is possible for a network admin rolling out a standard image to have the user's default locale set to one differing from the base OS installation, and thus the system default locale.

In this situation Windows' provides an alternate API you can use to obtain the LCID for the current user ... GetUserDefaultLCID. Defined identically to GetSystemDefaultLCID, GetUserDefaultLCID function retrieves the user default–locale identifier and is therefore the most appropriate API to use when it is the user's locale you are interested in, rather than that of the system.


 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter