Click here to Skip to main content
15,890,947 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
This is to produce a country list. This is the exact same list that is shown in the dropdown under Region & Language on the Location Tab.

I will include the VB6 code first, then the the VB.NET code that the VS2008 VB to VB.NET wizard made. Ultimatly I'd like to convert it to C# but so far I've not been able to. You will see in the code listed that the VB6 to VB.NET conversion produced some upgrade warnings. Since I've not done alot of Win32 API calls I'm really not sure how to make this work in C#.

The wizard did include some HELP links but for some reason I can not get them to work.

VB6
modCountryList.bas

VB
Option Explicit
'working var
Public LCID As Long
'SYSGEOTYPE
Private Const GEO_FRIENDLYNAME As Long = &H8
'SYSGEOCLASS
Public Const GEOCLASS_NATION As Long = 16 'only valid GeoClass value
Public Declare Function GetUserDefaultLCID Lib "Kernel32" () As Long
Private Declare Function GetGeoInfo Lib "Kernel32" _
   Alias "GetGeoInfoA" _
  (ByVal geoid As Long, _
   ByVal GeoType As Long, _
   lpGeoData As Any, _
   ByVal cchData As Long, _
   ByVal langid As Long) As Long
   
Public Declare Function EnumSystemGeoID Lib "Kernel32" _
  (ByVal geoclass As Long, _
   ByVal ParentGeoId As Long, _
   ByVal lpGeoEnumProc As Long) As Long
   
Private Declare Function lstrlenW Lib "Kernel32" _
  (ByVal lpString As Long) As Long

Public Function EnumGeoInfoProc(ByVal geoid As Long) As Long
  'add the data to the list
   With frmCountryList.List1
   
     'if the GeoId returned from the Enum
     'matches the GeoId determined at Load
     'for the user, append a string to that
     'combo item and record the list index
     'of that item
      .AddItem GetGeoFriendlyName(geoid, LCID)
         
   End With
   
  'return 1 to continue enumeration
   EnumGeoInfoProc = 1
   
End Function

Private Function GetGeoFriendlyName(geoclass As Long, LCID As Long) As String
   Dim lpGeoData As String
   Dim cchData As Long
   Dim nRequired As Long
   
   lpGeoData = ""
   cchData = 0
   
  'call once with an empty string; the return
  'value indicates the size of the buffer required
   nRequired = GetGeoInfo(geoclass, GEO_FRIENDLYNAME, ByVal lpGeoData, cchData, LCID)
   
   If (nRequired > 0) Then
      
      lpGeoData = Space$(nRequired)
      cchData = nRequired
        
      Call GetGeoInfo(geoclass, GEO_FRIENDLYNAME, ByVal lpGeoData, cchData, LCID)
      GetGeoFriendlyName = TrimNull(lpGeoData)
      
   End If
   
End Function

Private Function TrimNull(startstr As String) As String
   TrimNull = Left$(startstr, lstrlenW(StrPtr(startstr)))
   
End Function


frmCountryList.frm
VB
Private Sub Form_Load()

    LCID = GetUserDefaultLCID()
    Call EnumSystemGeoID(GEOCLASS_NATION, 0&, AddressOf EnumGeoInfoProc)

End Sub


VB.NET
modCountryList.vb
VB
Option Strict Off
Option Explicit On
Module modCountryList
    'working var
    Public LCID As Integer

    'SYSGEOTYPE
    Private Const GEO_FRIENDLYNAME As Integer = &H8

    'SYSGEOCLASS
    Public Const GEOCLASS_NATION As Integer = 16 'only valid GeoClass value

    Public Declare Function GetUserDefaultLCID Lib "Kernel32" () As Integer

    'UPGRADE_ISSUE: Declaring a parameter 'As Any' is not supported. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="FAE78A8D-8978-4FD4-8208-5B7324A8F795"'
    Private Declare Function GetGeoInfo Lib "Kernel32"  Alias "GetGeoInfoA"(ByVal geoid As Integer, ByVal GeoType As Integer, ByRef lpGeoData As Any, ByVal cchData As Integer, ByVal langid As Integer) As Integer

    Public Declare Function EnumSystemGeoID Lib "Kernel32" (ByVal geoclass As Integer, ByVal ParentGeoId As Integer, ByVal lpGeoEnumProc As Integer) As Integer

    Private Declare Function lstrlenW Lib "Kernel32" (ByVal lpString As Integer) As Integer



    Public Function EnumGeoInfoProc(ByVal geoid As Integer) As Integer

        'add the data to the list
        With frmCountryList.List1

            'if the GeoId returned from the Enum
            'matches the GeoId determined at Load
            'for the user, append a string to that
            'combo item and record the list index
            'of that item
            .Items.Add(GetGeoFriendlyName(geoid, LCID))

        End With

        'return 1 to continue enumeration
        EnumGeoInfoProc = 1

    End Function


    Private Function GetGeoFriendlyName(ByRef geoclass As Integer, ByRef LCID As Integer) As String

        Dim lpGeoData As String
        Dim cchData As Integer
        Dim nRequired As Integer

        lpGeoData = ""
        cchData = 0

        'call once with an empty string; the return
        'value indicates the size of the buffer required
        nRequired = GetGeoInfo(geoclass, GEO_FRIENDLYNAME, lpGeoData, cchData, LCID)

        If (nRequired > 0) Then

            lpGeoData = Space(nRequired)
            cchData = nRequired

            Call GetGeoInfo(geoclass, GEO_FRIENDLYNAME, lpGeoData, cchData, LCID)
            GetGeoFriendlyName = TrimNull(lpGeoData)

        End If

    End Function


    Private Function TrimNull(ByRef startstr As String) As String

        'UPGRADE_ISSUE: StrPtr function is not supported. Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="367764E5-F3F8-4E43-AC3E-7FE0B5E074E2"'
        TrimNull = Left(startstr, lstrlenW(StrPtr(startstr)))

    End Function
End Module


frmCountryList.vb
VB
Option Strict Off
Option Explicit On
Friend Class frmCountryList
    Inherits System.Windows.Forms.Form
    Private Sub frmCountryList_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load

        LCID = GetUserDefaultLCID()
        'UPGRADE_WARNING: Add a delegate for AddressOf EnumGeoInfoProc Click for more: 'ms-help://MS.VSCC.v90/dv_commoner/local/redirect.htm?keyword="E9E157F7-EF0C-4016-87B7-7D7FBBC6EE08"'
        Call EnumSystemGeoID(GEOCLASS_NATION, 0, AddressOf EnumGeoInfoProc)

    End Sub
End Class
Posted

You have 4 Win32 API functions:
1. GetUserDefaultLCID
2. GetGeoInfo
3. EnumSystemGeoID
4. lstrlenW

From what I can understand, your problem is "ByRef lpGeoData As Any" parameter in GetGeoInfo. These kind of problems come when the converter is not able to identify appropriate type for the variable.
As per MSDN Documentation this parameter should be of lpstr type for which you can use either "UnmanagedType.LPStr" or "String" or "StringBuilder" type in C#.

As far as working with Win32 API calls is concerned, you should be aware of the dll (containing required method) and method parameters. For syntax you can go through this article.

Hope this helps.
 
Share this answer
 
v2
Totally untested, but using the function and delegate declarations from MSDN I come up with this for the P/Invoke side of things.
C#
using System.Runtime.InteropServices;
using System.Text;

internal static class NativeMethods
{
    public const int GEOCLASS_NATION = 0x10;
    // http://msdn.microsoft.com/en-us/library/dd318135(v=vs.85).aspx
    /*
LCID GetUserDefaultLCID(void);
     */
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern int GetUserDefaultLCID();
    // http://msdn.microsoft.com/en-us/library/dd318099(v=vs.85).aspx
    /*
int GetGeoInfo(
  __in   GEOID Location,
  __in   GEOTYPE GeoType,
  __out  LPTSTR lpGeoData,
  __in   int cchData,
  __in   LANGID LangId
);
     */
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern int GetGeoInfo(int Location, SYSGEOTYPE GeoType, StringBuilder lpGeoData, int cchData, int LangId);
    // http://msdn.microsoft.com/en-us/library/dd317826(v=vs.85).aspx
    /*
BOOL EnumSystemGeoID(
  __in  GEOCLASS GeoClass,
  __in  GEOID ParentGeoId,
  __in  GEO_ENUMPROC lpGeoEnumProc
);
     */
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern int EnumSystemGeoID(int GeoClass, int ParentGeoId, EnumGeoInfoProc lpGeoEnumProc);
    // http://msdn.microsoft.com/en-us/library/ms647492(v=vs.85).aspx
    /*
int WINAPI lstrlen(
  __in  LPCTSTR lpString
);
     */
    [DllImport("Kernel32.dll", SetLastError = true)]
    public static extern int lstrlen(string lpString);
    // http://msdn.microsoft.com/en-us/library/dd317817(v=vs.85).aspx
    /*
BOOL CALLBACK EnumGeoInfoProc(
  __in  GEOID GeoId
);
     */
    public delegate bool EnumGeoInfoProc(int GeoId);
}
// http://msdn.microsoft.com/en-us/library/dd374071(v=vs.85).aspx
public enum SYSGEOTYPE
{
    GEO_NATION = 0x0001,
    GEO_LATITUDE = 0x0002,
    GEO_LONGITUDE = 0x0003,
    GEO_ISO2 = 0x0004,
    GEO_ISO3 = 0x0005,
    GEO_RFC1766 = 0x0006,
    GEO_LCID = 0x0007,
    GEO_FRIENDLYNAME = 0x0008,
    GEO_OFFICIALNAME = 0x0009,
    GEO_TIMEZONES = 0x000A,
    GEO_OFFICIALLANGUAGES = 0x000B
}

Before calling GetGeoInfo, create a StringBuilder and set an initial capacity. Pass the StringBuilder instance to lpGeoData and it's capacity to cchData.
 
Share this answer
 
Comments
MrSmoofy 24-Jun-11 15:12pm    
PERFECT! I was able to take what you provided here add a little to it for linking in a handler to the delgate and passing that to the WIN32 function for the call back and WAMO! Exactly what I needed I can't begin to thank you enough for this!
You can use some code converter

Telerik Code Converter[^]

Thanks.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900